I'm trying to implement the following method:
void Ball::DrawOn(Graphics g);
The method should draw all previous locations (stored in a queue) of the ball and finally the current location. I don't know if that matters, but I print the previous locations using g.DrawEllipse(...) and the current location using g.FillEllipse(...).
The question is, that as you could imagine there is a lot of drawing to be done and thus the display starts to flicker much. I had searched for a way to double buffer, but all I could find is these 2 ways:
System.Windows.Forms.Control.DoubleBuffered = true;
SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
while trying to use the first, I get the an error explaining that from in this method the Property DoubleBuffered is inaccessible due to its protection level. While I can't figure how to use the SetStyle method.
Is it possible at all to double buffer while all the access I have is to the Graphics Object I get as input in the method?
Thanks in Advance,
Edit:
I had created the following class
namespace doubleBuffer
{
class BufferedBall : System.Windows.Forms.Form
{
private Ball ball;
public BufferedBall(Ball ball)
{
this.ball = ball;
}
public void DrawOn(Graphics g)
{
this.DoubleBuffered = true;
int num = 0;
Rectangle drawArea1 = new Rectangle(5, 35, 30, 100);
LinearGradientBrush linearBrush1 =
new LinearGradientBrush(drawArea1, Color.Green, Color.Orange, LinearGradientMode.Horizontal);
Rectangle drawArea2 = new Rectangle(5, 35, 30, 100);
LinearGradientBrush linearBrush2 =
new LinearGradientBrush(drawArea2, Color.Black, Color.Red, LinearGradientMode.Vertical);
foreach (Point point in ball.previousLocations)
{
Pen myPen1;
if (num % 3 == 0)
myPen1 = new Pen(Color.Yellow, 1F);
else if (num % 3 == 1)
myPen1 = new Pen(Color.Green, 2F);
else
myPen1 = new Pen(Color.Red, 3F);
num++;
myPen1.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
myPen1.StartCap = System.Drawing.Drawing2D.LineCap.RoundAnchor;
myPen1.EndCap = System.Drawing.Drawing2D.LineCap.AnchorMask;
g.DrawEllipse(myPen1, (float)(point.X - ball.radius), (float)(point.Y + ball.radius), (float)(2 * ball.radius), (float)(2 * ball.radius));
}
if ((ball.Host.ElapsedTime * ball.Host.FPS * 10) % 2 == 0)
{
g.FillEllipse(linearBrush1, (float)(ball.Location.X - ball.radius), (float)(ball.Location.Y + ball.radius), (float)(2 * ball.radius), (float)(2 * ball.radius));
}
else
{
g.FillEllipse(linearBrush2, (float)(ball.Location.X - ball.radius), (float)(ball.Location.Y + ball.radius), (float)(2 * ball.radius), (float)(2 * ball.radius));
}
}
}
}
and the ball drawOn looks like this:
new BufferedBall(this).DrawOn(g);
Is that what you meant? because it is still flickering?
Form class has DoubleBuffered property exposed as protected. http://msdn.microsoft.com/en-us/library/system.windows.forms.control.doublebuffered.aspx but since you derive your form from Form you can use it.
this.DoubleBuffered = true;
That's fine but you have to move this statement to the constructor. Double-buffering requires setup, Windows Forms has to create a buffer, that must be done before the paint event runs. The constructor is ideal.
A simpler way to set style for double buffering of Control-derived classes is to use reflection. See here: http://www.csharp-examples.net/set-doublebuffered/
That would save you the step of subclassing a control just to set a protected property.
You don't need to set DoubleBuffered to true each time you redraw. It is not disabled when drawing finished. Just remove the line from DrawOn and set it in the constructor or Forms Designer and check the results. Setting the value to false produces significant flickering while setting to true doesn't.
I tried your code in a form where a timer forces a redraw every millisecond and noticed no flickering when DoubleBuffered is true:
private int yDir = 1,xDir=1;
int step = 1;
private void timer1_Tick(object sender, EventArgs e)
{
if (ball.Location.Y >= this.Height-50)
yDir = -1 ;
if (ball.Location.X >= this.Width-50)
xDir= -1 ;
ball.MoveBy(xDir*step,yDir*step);
ball.Host.ElapsedTime++;
this.Invalidate();
}
private void DoubleBufferedBall_Paint(object sender, PaintEventArgs e)
{
DrawOn(e.Graphics);
}
Another option, that I'll toss out for you, is to do all your drawing to a Bitmap, and then in the OnPaint method, you simply draw that Bitmap to the form.
Its manual, but it gives you full control. I've used it with some success on some pet projects of mine.
You also might want to look into XNA -- it might be overkill for your project here, but you can use XNA in WinForms as a rendering engine.
Related
Today im doing the pixels in the paint event to blink.
In form1 i have this code in a timer tick event that the interval is set to 1000ms.
private void timer1_Tick(object sender, EventArgs e)
{
CloudEnteringAlert.cloudColorIndex = (CloudEnteringAlert.cloudColorIndex + 1) % CloudEnteringAlert.cloudColors.Length;
pictureBox1.Invalidate();
}
In the CloudEntering class i have on the top:
public static Brush[] cloudColors = new[] { Brushes.Yellow, Brushes.Transparent };
Then in a paint method this paint method im calling from the form1 pictureBox1 paint event:
foreach (PointF pt in clouds)
{
e.FillEllipse(cloudColors[cloudColorIndex], pt.X * (float)currentFactor, pt.Y * (float)currentFactor, 7f, 7f);
}
So what i see now is one second the pixels are in yellow and one second the pixels are in Transparent.
Now what i want to do is:
Each pixel will start from radius 5.
Each pixel radius will get bigger to 25.
The animation will be from the top to the bottom.
Each pixel that got to radius 25 will start to get smaller back to radius 5.
When the first pixel is started from 5 will get to radius 15 the next one will start to get bigger.
So if the first pixel is start at 5 now its 15 the next one will start to get bigger and the first one will continue to 25 when the first one is 25 it will get smaller. The second one when its 15 the third one will get bigger and so on.
All the pixels will start at radius 5 but only the first one will start get bigger get to 15 then the next one and when the first is 25 it will get smaller .
This is the time between each pixel.
And each pixel radius size change should take 300ms !
How can i do it ?
You want to start by encapsulating all information needed to render a single ellipse into a separate class. That would be something like:
public class Ellipse
{
public PointF Center { get; set; }
public Brush Brush { get; set; }
public float Diameter { get; set; }
public float DiameterDelta { get; set; }
public Ellipse(float x, float y)
{
Center = new PointF(x, y);
Brush = Brushes.Blue;
Diameter = 5;
DiameterDelta = 1;
}
}
The Ellipse.DiameterDelta property is the delta value which will be used for animation, and it can be positive (when going from diameter 5 to diameter 25), or negative (when going backwards). The value of this property (I've used 1 above) together with the your Timer.Interval will influence the speed of your animation.
A better OOP design would probably advocate moving animation-related properties out of this class, but for simplicity sake, it's better to start with this.
In your timer event, you might have something like:
private void timer_Tick(object sender, EventArgs e)
{
// presuming that you made a separate user control
// which has a collection of ellipses in a `Clouds` property
foreach (var c in cloudBox.Clouds)
Animate(c);
cloudBox.Invalidate();
}
private void Animate(Ellipse c)
{
// update diameter
c.Diameter += c.DiameterDelta;
// when you reach bounds, change delta direction
if ((c.DiameterDelta < 0 && c.Diameter <= 5) ||
(c.DiameterDelta > 0 && c.Diameter >= 25))
c.DiameterDelta = -c.DiameterDelta;
}
To get a smooth, non flickering animation, you will most likely have to use a custom control with ControlStyles.AllPaintingInWmPaint and ControlStyles.OptimizedDoubleBuffer set in its constructor, so instead of a PictureBox, I would do something like:
public partial class CloudBox : UserControl
{
public CloudBox()
{
InitializeComponent();
SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.ResizeRedraw, true);
}
private readonly List<Ellipse> _clouds = new List<Ellipse>();
public List<Ellipse> Clouds
{
get { return _clouds; }
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
foreach (var cloud in _clouds)
{
e.Graphics.FillEllipse(
cloud.Brush, cloud.Center.X, cloud.Center.Y,
cloud.Diameter, cloud.Diameter);
}
base.OnPaint(e);
}
}
I haven't tested this, but I believe you'll be able to fill in the details. Setting Timer.Interval to 10 or 20 ms should yield a pretty fluid animation IMHO.
[Edit] To instantiate the whole thing with some test data (I don't know where you get it from), you could use something like this in your Form.Load event handler:
for (int i = 0; i < 400; i += 50)
for (int j = 0; j < 400; j += 50)
cloudBox.Clouds.Add(new Ellipse(i, j));
I found this small application that i've been playing around with for the past little while. I was wondering, if i wanted to simply rotate the image in a circle? or make the entire image just bounce up and down, how would i modify this program to do so? Everything i've tried will just stretch the image - even if i do get it to move to the left or to the right. Any ideas on what i can do? Code is below
public partial class Form1 : Form
{
private int width = 15;
private int height = 15;
Image pic = Image.FromFile("402.png");
private Button abort = new Button();
Thread t;
public Form1()
{
abort.Text = "Abort";
abort.Location = new Point(190, 230);
abort.Click += new EventHandler(Abort_Click);
Controls.Add(abort);
SetStyle(ControlStyles.DoubleBuffer| ControlStyles.AllPaintingInWmPaint| ControlStyles.UserPaint, true);
t = new Thread(new ThreadStart(Run));
t.Start();
}
protected void Abort_Click(object sender, EventArgs e)
{
t.Abort();
}
protected override void OnPaint( PaintEventArgs e )
{
Graphics g = e.Graphics;
g.DrawImage(pic, 10, 10, width, height);
base.OnPaint(e);
}
public void Run()
{
while (true)
{
for(int i = 0; i < 200; i++)
{
width += 5;
Invalidate();
Thread.Sleep(30);
}
}
}
}
So I don't know what you're trying to achieve, but to get the fundies out of the way, WinForms is a GDI+ library and its meant more for GUI stuff, so something like animation will probably be handled better by a graphics library like SFML.
Anyways, there's a million ways to achieve what you want. In terms of moving something around in a circle, you're gonna need a little simple trig. For a bouncing motion, I would say following a sine curve would be the easiest way.
Here's some pseudo-code (not sure if this is syntax-perfect) for bouncing:
Field Definitions:
private double frame = 0;
OnPaint:
Graphics g = e.Graphics;
g.DrawImage(pic, 10, 10 + Math.sin(frame)*10, width, height);
frame+=.01;
base.OnPaint(e);
This way, every time the paint event is triggered, t will increase by .01 radians. The sin has a domain that will oscillate between -1 and 1, and you can multiply that by a factor of 10 to get that bouncing effect.
Frame represents your "keyframe". If you want to speed it up, increase the frame+=__ to a higher value. If you want to increase the range, change the offset Math.sin(frame)*__
Why does the paint even take so long?
public Form1()
{
InitializeComponent();
SuspendLayout();
double scale = ClientSize.Width / 11;
for (int i = 1; i < 10; i++)
{
for (int j = 1; j < 10; j++)
{
everybox[i - 1, j - 1] = new TextBox
{
Location = new Point((int)(scale * i), (int)(scale * j)),
Size = new Size((int)scale - 2, (int)scale - 2),
Multiline = true
};
Controls.Add(everybox[i - 1, j - 1]);
}
}
ResumeLayout();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
float scale = ClientSize.Width / 11;
Graphics g = this.CreateGraphics();
int counter = 0;
for (float i = scale; i <= this.ClientSize.Width - scale; i += scale)
{
counter++;
if ((counter - 1) % 3 != 0)
{
g.DrawLine(new Pen(Color.Black), new Point((int)i, (int)scale),
new Point((int)i, ClientSize.Width - (int)scale));
g.DrawLine(new Pen(Color.Black), new Point((int)scale, (int)i),
new Point(ClientSize.Width - (int)scale, (int)i));
}
else
{
g.DrawLine(new Pen(Color.Black, 3f), new Point((int)i, (int)scale),
new Point((int)i, ClientSize.Width - (int)scale));
g.DrawLine(new Pen(Color.Black, 3f), new Point((int)scale, (int)i),
new Point(ClientSize.Width - (int)scale, (int)i));
}
}
}
It is rather annoying, and causes noticeable lag. everybox is a TextBox[9,9] object.
Per my comment, change:
Graphics g = this.CreateGraphics();
to
e.Graphics
Paint can definitely get called alot and if you are getting too many calls, it probably has nothing to do with this bit of code. One thing that would help the performance of this particular bit is to try reducing the amount of work you do...
Graphics g = e.Graphics;
Pen bp = new Pen(Color.Black, 3f);
Point start = new Point(0,0);
Point stop = new Point(0,0);
for (float i = scale; i <= this.ClientSize.Width - scale; i += scale)
{
int iAsInt = (int)i;
int scaleAsInt = (int)scale;
int w = ClientSize.Width;
counter++;
if ((counter - 1) % 3 != 0)
{
start.X = iAsInt;
start.Y = scaleAsInt;
stop.X = iAsInt;
stop.Y = w-scaleAsInt;
g.DrawLine(Pens.Black, start, stop);
start.X = scaleAsInt;
start.Y = iAsInt;
stop.X = w-scaleAsInt;
stop.Y = iAsInt;
g.DrawLine(Pens.Black, start, stop);
// Note: this looks like more work, but it is actually less
// your code still has to make all the assignments in addition to
// newing up the points (and later having to garbage collect them)
}
else
{
// TODO: reuse the start/stop points here
g.DrawLine(bp, new Point(iAsInt, scaleAsInt), new Point(iAsInt, w - scaleAsInt);
g.DrawLine(bp, new Point(scaleAsInt, iAsInt), new Point(w - scaleAsInt, iAsInt));
}
}
To specifically stop the overdrawing of your lines, look at the ClipRectangle member of PaintEventArgs. If part of your line falls within the area of the clip rectangle, redraw it.
A possible reason is because you are trying to draw too many heavy-weight components. If my math is correct you are redrawing 9 * 9 * 9 * 9 = 6561 objects. WinForms are not designed to support redrawing of that many components in the efficient way.
You may need to think if you really need to use that many heavy-weight graphic components with WinForms. There might be lighter components or you can switch to XNA (which has camera, views etc - all of that reduce the number of objects needed to be redrawn) or WPF depending on the context.
The code you posted causes the paint event to fire 81 times (9*9). Once for each control being added to the form. Any more times are due to something that invalidates the form, like the mouse moving over it, another window moving over it, or the form resizing. Some code you aren't showing us may be responsible.
Is it possible to rotate a button or any control at a particular angle in WinForms? If so, how?
If you really want to (I have no idea why one would..*) you could try to use a Button subclass, maybe like that:
public partial class TurnButton : Button
{
public TurnButton()
{
InitializeComponent();
}
int angle = 0; // current rotation
Point oMid; // original center
protected override void OnLayout(LayoutEventArgs levent)
{
base.OnLayout(levent);
if (oMid == Point.Empty) oMid = new Point(Left + Width / 2, Top + Height / 2);
}
protected override void OnPaint(PaintEventArgs pe)
{
int mx = this.Size.Width / 2;
int my = this.Size.Height / 2;
SizeF size = pe.Graphics.MeasureString(Text, Font);
string t_ = Text;
Text = "";
base.OnPaint(pe);
if (!this.DesignMode)
{
Text = t_; pe.Graphics.TranslateTransform(mx, my);
pe.Graphics.RotateTransform(angle);
pe.Graphics.TranslateTransform(-mx, -my);
pe.Graphics.DrawString(Text, Font, SystemBrushes.ControlText,
mx - (int)size.Width / 2, my - (int)size.Height / 2);
}
}
protected override void OnClick(EventArgs e)
{
this.Size = new Size(Height, Width);
this.Location = new Point(oMid.X - Width / 2, oMid.Y - Height / 2);
angle = (angle + 90) % 360;
Text = angle + "°";
base.OnClick(e);
}
}
(* I have no idea why I wrote that, either ;-)
You can't rotate controls. That's simply not supported by the native API controls that WinForms uses.
And one might wonder why it even should be supported. What could you possibly be trying to do that you'd need to rotate a button control? It would be much easier to draw it in a different place with a different shape in the first place, rather than trying to rotate an existing control. (Do note that you can also resize and reposition a control at run-time, if that would fit your needs. Investigate the Size and Location properties.)
The only workaround is to draw the control's image to a bitmap, hide the control, and draw the bitmap onto the form in the location you want it to appear. Of course, that won't result in a control that the user can interact with. They won't be able to click an image of a button, because it's not a real button. If that's acceptable to you, you should probably be using an image in the first place, rather than a button.
This is similar to the question asked here:
Rotating a .NET panel in Windows Forms
The quick summary of answers from that question is that while it may be possible to do it, it would be very, very complicated.
A possible workaround in some cases would be this:
Use a tabControl , and resize it so you only have the button left. Set the allignment to left/right, and you have your button rotated 90/270 degrees.
public class VerticalButton : Button
{
public string VirticalText { get; set; }
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
StringFormat stringFormat = new StringFormat();
stringFormat.FormatFlags = StringFormatFlags.DirectionVertical;
SolidBrush solidBrush = new SolidBrush(this.ForeColor);
stringFormat.Alignment = StringAlignment.Center;
stringFormat.LineAlignment = StringAlignment.Center;
pe.Graphics.DrawString(VirticalText, this.Font, solidBrush,
new Rectangle(0, 0, Width, Height), stringFormat);
}
}
// here is the full code.
// I would expect the btnLine_Click() method to start the timer (which it does) and then
// accept "angle" from the "public float myangle" getter but it does not. So it only draws // one 30 degree hard coded line. I desire the line to be incremented around in 10
// degree steps sort of like the second hands of a clock.
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Drawing.Imaging;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.IO;
using System.Text;
namespace DrawingShapesApp
{
public class Form1 : Form
{
private Bitmap DrawingArea;
private Pen myPen;
private System.Windows.Forms.Timer timer1;
private System.ComponentModel.IContainer components;
private Button btnLine;
float angle;
public float x1=300; // 1st point pair
public float y1=500;
public float x2=500; // 2nd point pair
public float y2=300;
public double angleX = 30; // 30 degrees
public double Xdist;
public double sqrt;
public Form1()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
private void InitializeComponent()
{
this.ClientSize = new System.Drawing.Size(800, 650);
this.Text="line5";
this.components = new System.ComponentModel.Container();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
btnLine = new Button();
this.btnLine.Location = new System.Drawing.Point(8, 88);
this.btnLine.Name = "btnLine";
this.btnLine.Size = new System.Drawing.Size(40, 40);
this.btnLine.TabIndex = 1;
this.btnLine.Text = "Step";
this.Controls.Add(this.btnLine);
// Load this "frmGraphics_Load" at load time
this.Load += new System.EventHandler(this.frmGraphics_Load);
this.Closed += new System.EventHandler(this.frmGraphics_Closed);
this.Paint += new System.Windows.Forms.PaintEventHandler(this.frmGraphics_Paint);
this.ResumeLayout(false);
myPen = new Pen(Color.Blue);
this.btnLine.Click += new System.EventHandler(this.btnLine_Click);
}
static void Main()
{
Application.Run(new Form1());
}
private void frmGraphics_Load(object sender, System.EventArgs e) // a clickable event
{
Console.WriteLine("First...load this: frmGraphics_Load");
// create a new bitmap...defining the bitmap the same size as the form
DrawingArea = new Bitmap(
this.ClientRectangle.Width,
this.ClientRectangle.Height,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
InitializeDrawingArea();
}
// copy from bitmap to the form
private void InitializeDrawingArea()
{
Graphics oGraphics; // oGraphics is the form
oGraphics = Graphics.FromImage(DrawingArea); // copy bitmap to form
myPen.Color = Color.AliceBlue;
for ( int x = 0; x 359)
angle=0;
Console.WriteLine("**timer1 angle= {0}", angle);
float myangle = angle;
if(angle == 90)
this.timer1.Enabled = false;
Invalidate();
}
public float myangle
{
set { angle = value; }
get { return angle; }
}
private void btnLine_Click(object sender, System.EventArgs e)
{
this.timer1.Enabled = true;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
// timer now active...why does it not take the angle from timer1_Tick() ?
// I need to increment the drawline by 10 degrees like the hand of a clock
Console.WriteLine("in btnLine_Click");
// draws a hardcoded line but cannot get "angle" from timer1_Tick()
Graphics oGraphics;
oGraphics = Graphics.FromImage(DrawingArea); // copy from bitmap to form
Pen Grn = new Pen(Color.Green, 2);
Pen penBlue = new Pen(Color.Blue, 1);
Rectangle rect = new Rectangle(100, 100, 400, 400); // draw circle
oGraphics.DrawEllipse( penBlue, rect );
oGraphics.DrawLine(Grn, 300, 300, 500, 300); // draw horiz. line
PointF p1 = new PointF(x1, y1);
PointF p2 = new PointF(x2, y2);
double Xdist = Math.Abs(p2.X - p1.X);
Console.WriteLine("Xdist= {0}", Xdist);
double angle30 = Math.Cos(DegreeToRadian(30)); // need myangle in place of 30
Console.WriteLine("angle30= {0}", angle30);
double side_c = Math.Tan(DegreeToRadian(angleX)) * Xdist;
Console.WriteLine("side_c= {0}", side_c);
sqrt = (Xdist*Xdist + side_c*side_c);
double side_a = Math.Sqrt(sqrt);
Console.WriteLine("side_a= {0}", side_a);
// this draws a
oGraphics.DrawLine(Grn, 300, 300, 300+(float)173.21, 300-100); // intersects circle
oGraphics.DrawLine(Grn, 300+(float)173.21, 300, 300+(float)173.21, 300-100); // draw vert. line
oGraphics.Dispose(); // clean up graphics object
this.Invalidate(); // force form to redraw itself
}
private double DegreeToRadian(double angle)
{
return Math.PI * angle / 180.0;
}
private double RadianToDegree(double angle)
{
return angle * (180.0 / Math.PI);
}
public void timer_stop()
{
Console.WriteLine("Halting timer!");
this.timer1.Enabled = false; // halts operation
}
}
}
Maybe just maybe your timer does > 359 in which Total is reset to 0. Could that be the case?
It also appears you are trying to use properties when working with some variables.
Include a set inside of total, it helps other programmers understand exactly what you are doing.
public float Total { get { return angle; } set { angle = value; } }
Then change
float Total = angle;
to
Total = angle;
What you originally have is you've declared a local variable called Total, and that value is gone once you've reached the scope of that function. In order to maintain the value you want to set the property Total with the value of angle.
Also in the future you may want to be a bit more detailed about your issue. You need to post more relevant code like what is inside Invalidate(). And I've edited your question, when posting code samples use the little binary 0's and 1's to seperate code from actual content. It helps the people who want to help you :).
I almost honestly think your timer gets its values because that condition (if condition) is satisfied and angle is reset to 0. Otherwise, you will need to post Invalidate() to see if that changes the value of angle.
If your timer is running very often, perhaps you have mixed up your calculation of the interval, then it would run so often that it would quickly pass 359 and then be set to 0, and then the cycle would start again. As mentioned, set a breakpoint. Put it on the Invalidate statement and then mouse over Angle and see what it's value is.
Also float Total=angle; isn't accomplishing anything because Total is a local variable in this context and never gets used.
Since no answer form the original poster here what might possibly be wrong.
The timer is not started. (from my comment)
Setting the variable angle volatile might fix the problem. Usually, when reading/writing a variable from different threads, it might happen that the value is not updated.
Hope this help.