C
christer.dk
Hi all,
We're doing an application in which a background agent is polling
asynchronously for data and doing some work. When having new data it
throws an event. A method is wired to the event, uses Invoke for
updating selected datagrids etc. However, sometimes, the user is doing
work (like executing a save method at the same time), and we want to
postpone the redraw of the datagrids, or delay users input a little
until updating is completed. All in all, we want to "syncronize" the
events regarding updating and workm and what is shown.
I may be misunderstanding the use of the lock statement, but basicaly
the logic behind the code below is that if a lock statement is entered
using the thelock object, other lock statments using the same object
are put in "queue" and waits until the previous lock statement is
exited.
The code below is a form with two buttons. The first button starts a
thread, simulating the agent throwing the event. The eventhandler uses
Invoke to invoke Cross. The Cross method does some work (not a all near
15 seconds in real life, this is for show only). While entering and
working (before the 15 seconds have past), the second button is
pressed. I would expect the second buttons event handler to wait at the
lock statement until the Cross method releases it, but I get this
result:
15:31:58: Cross entering lock
15:31:58: Cross entered lock
15:31:59: Button2 entering lock
15:31:59: Button2 entered lock
15:32:00: Button2 exited lock
15:32:14: Cross exited lock
My expected result would be:
Cross entering lock
Cross entered lock
Cross exited lock
Button2 entering lock
Button2 entered lock
Button2 exited lock
or vice versa, regarding whoever comes first... but not mixed...
After some testing I'm wondering if this is only valid as an idea. Is
this the right way to do what I want? Am I misunderstanding the lock
(is the lock only usable on the same code, not scattered locks in
several methods? I have however seen property accessors that uses the
same lock object, so...)
PS. The while statement with sleep and DoEvents might also be wrong for
simulating work while still being able to take input from the user.
Maybe the example is done wrong, and the methods actually would be
synchronized in a real situation?
You're welcome to answer me in hard technical terms, I'm just fairly
new to threaded windows programming...
Thanks in advance!
Christer
public partial class Form1 : Form
{
private object thelock;
public Form1()
{
thelock = new object();
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//Start worker thread
ThreadStart ts = new ThreadStart(ThreadWork);
Thread thread = new Thread(ts);
thread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
Debug.Write(DateTime.Now.ToLongTimeString() + ": Button2
entering lock" + Environment.NewLine);
lock (thelock)
{
Debug.Write(DateTime.Now.ToLongTimeString() + ":
Button2 entered lock" + Environment.NewLine);
MessageBox.Show("Button executed");
}
Debug.Write(DateTime.Now.ToLongTimeString() + ": Button2
exited lock" + Environment.NewLine);
}
private void ThreadWork()
{
this.Invoke(new MethodInvoker(Cross));
}
private void Cross()
{
Debug.Write(DateTime.Now.ToLongTimeString() + ": Cross
entering lock" + Environment.NewLine);
lock (thelock)
{
Debug.Write(DateTime.Now.ToLongTimeString() + ": Cross
entered lock" + Environment.NewLine);
DateTime seconds15 = DateTime.Now.AddSeconds(15);
//Wait 15 seconds...
while (DateTime.Now < seconds15)
{
Thread.Sleep(15);
Application.DoEvents();
}
MessageBox.Show("Cross executed");
}
Debug.Write(DateTime.Now.ToLongTimeString() + ": Cross
exited lock" + Environment.NewLine);
}
}
We're doing an application in which a background agent is polling
asynchronously for data and doing some work. When having new data it
throws an event. A method is wired to the event, uses Invoke for
updating selected datagrids etc. However, sometimes, the user is doing
work (like executing a save method at the same time), and we want to
postpone the redraw of the datagrids, or delay users input a little
until updating is completed. All in all, we want to "syncronize" the
events regarding updating and workm and what is shown.
I may be misunderstanding the use of the lock statement, but basicaly
the logic behind the code below is that if a lock statement is entered
using the thelock object, other lock statments using the same object
are put in "queue" and waits until the previous lock statement is
exited.
The code below is a form with two buttons. The first button starts a
thread, simulating the agent throwing the event. The eventhandler uses
Invoke to invoke Cross. The Cross method does some work (not a all near
15 seconds in real life, this is for show only). While entering and
working (before the 15 seconds have past), the second button is
pressed. I would expect the second buttons event handler to wait at the
lock statement until the Cross method releases it, but I get this
result:
15:31:58: Cross entering lock
15:31:58: Cross entered lock
15:31:59: Button2 entering lock
15:31:59: Button2 entered lock
15:32:00: Button2 exited lock
15:32:14: Cross exited lock
My expected result would be:
Cross entering lock
Cross entered lock
Cross exited lock
Button2 entering lock
Button2 entered lock
Button2 exited lock
or vice versa, regarding whoever comes first... but not mixed...
After some testing I'm wondering if this is only valid as an idea. Is
this the right way to do what I want? Am I misunderstanding the lock
(is the lock only usable on the same code, not scattered locks in
several methods? I have however seen property accessors that uses the
same lock object, so...)
PS. The while statement with sleep and DoEvents might also be wrong for
simulating work while still being able to take input from the user.
Maybe the example is done wrong, and the methods actually would be
synchronized in a real situation?
You're welcome to answer me in hard technical terms, I'm just fairly
new to threaded windows programming...
Thanks in advance!
Christer
public partial class Form1 : Form
{
private object thelock;
public Form1()
{
thelock = new object();
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//Start worker thread
ThreadStart ts = new ThreadStart(ThreadWork);
Thread thread = new Thread(ts);
thread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
Debug.Write(DateTime.Now.ToLongTimeString() + ": Button2
entering lock" + Environment.NewLine);
lock (thelock)
{
Debug.Write(DateTime.Now.ToLongTimeString() + ":
Button2 entered lock" + Environment.NewLine);
MessageBox.Show("Button executed");
}
Debug.Write(DateTime.Now.ToLongTimeString() + ": Button2
exited lock" + Environment.NewLine);
}
private void ThreadWork()
{
this.Invoke(new MethodInvoker(Cross));
}
private void Cross()
{
Debug.Write(DateTime.Now.ToLongTimeString() + ": Cross
entering lock" + Environment.NewLine);
lock (thelock)
{
Debug.Write(DateTime.Now.ToLongTimeString() + ": Cross
entered lock" + Environment.NewLine);
DateTime seconds15 = DateTime.Now.AddSeconds(15);
//Wait 15 seconds...
while (DateTime.Now < seconds15)
{
Thread.Sleep(15);
Application.DoEvents();
}
MessageBox.Show("Cross executed");
}
Debug.Write(DateTime.Now.ToLongTimeString() + ": Cross
exited lock" + Environment.NewLine);
}
}