The following piece of code has two threads each writing 20's string str
to its corresponding textbox. Once completed, Thread t00
signals Thread t01
to start and change the shared string str
from y to x. Thread t00
should write 20 y to a textbox, and Thread t01
should write 20 x to another textbox. Instead, Thread t00
end up writing 19 y and 1 x. But if I add a Thread.Sleep()
before EventWaitHandle is set, that fixes the problem I had (I get 20 x and 20 y), but why? EventWaitHandle
should not be set only after the loop is finished, with or without Thread.Sleep()
.
public partial class MainWindow : Window
{
public string str = "y";
static EventWaitHandle _waitHandle = new AutoResetEvent(false);
public MainWindow()
{
InitializeComponent();
Thread t00 = new Thread(() =>
{
for (int i = 0; i < 20; i++)
{
Thread.Sleep(200);
Action action00 = () =>
{
tb00.AppendText(str);
};
Dispatcher.BeginInvoke(action00);
}
Thread.Sleep(200); // <-- why this fix the problem??
_waitHandle.Set();
});
t00.Start();
Thread t01 = new Thread(() =>
{
Action action00 = () =>
{
tb01.AppendText("Waiting...\n");
};
Dispatcher.BeginInvoke(action00);
_waitHandle.WaitOne();
str = "x";
for (int i = 0; i < 20; i++)
{
Thread.Sleep(200);
Action action = () =>
{
tb01.AppendText(str);
};
Dispatcher.BeginInvoke(action);
}
});
t01.Start();
}
}
Because you are using BeginInvoke
. BeginInvoke
invokes delegate on UI thread asynchronously. It puts a message to UI thread message queue and returns, so the fact it returned does not mean action was actually executed.
For that reason, in most cases, when you set a wait handle and another thread recieves singal and changes str
from y
to x
- there is still non-invoked tb00.AppendText(str);
delegate in UI thread queue. When it finally is invoked - str
is already x
.
Thread.Sleep
"fixes" that, because it gives some time for that pending delegate to execute on UI thread. Using Invoke
instead of BeginInvoke
also "fixes" that, because Invoke
is synchronous and returns only after delegate has actually been executed on UI thread.