how to update label text in UI when multiple independent threads have executed. What is the use of Join
I have two independent functions that need to be executed on two different threads upon a button click on a window form.
As soon as both the threads gets executed completely the status on the Form should be set as "Status Updated."
How can I do this?
EDIT I am trying to run the following code and I am not able to figure out the issue. If I calls Join. My threads gets stuck infinity.
Thread t1, t2;
int cT1;
int ctT2;
private void btnStart_Click(object sender, EventArgs e)
{
t1 = new Thread(CountN);
t2 = new Thread(CountT2);
t1.Start(int.Parse(txtT1.Text)); //3
t2.Start(int.Parse(txtT2.Text)); //4
t2.Join();
label1.Text = (cT1 + ctT2).ToString();
}
private void CountN(object sender)
{
for (int i = 0; i < (int)sender; i++)
{
cT1++;
if (lblMsg.InvokeRequired)
lblMsg.Invoke(new Action<int>((x) => lblMsg.Text = x.ToString()), cT1);
}
}
private void CountT2(object sender)
{
for (int i = 0; i < (int)sender; i++)
{
ctT2++开发者_如何学运维;
if (lblMsg2.InvokeRequired)
lblMsg2.Invoke(new Action<int>((x) => lblMsg2.Text = x.ToString()), ctT2);
}
}
The UI thread and worker threads will deadlock because you have called Thread.Join
on the UI thread. Join
blocks the calling thread until the target thread completes. Since the block occurs on the UI thread it prevents the message pump from dispatching and processing windows messages. But, if the UI thread is ever blocked then this prevents this mechanism from happening. The worker threads also call Control.Invoke
which will marshal the execution of delegate onto the UI by sending a message to that thread's message queue and then wait for execution of that delegate to complete. But, if the UI thread is busy doing something, like blocking on a call to Join
, then that delegate will never complete and the Invoke
will block indefinitely. This situation leads to a scenario where Join
and Invoke
stalemate each other causing a deadlock.
The real problem here is the call to Join
from the UI thread. You should never call any blocking method from UI thread because it can lead to deadlocks and prevent the processing of windows messages like button clicks or rendering of the form. The user interface is completely hung up from the perspective of the end user.
To fix this problem remove the call to Join
and then just add another call to Control.Invoke
after the for
loops in the worker threads that execute logic that indicates that the worker threads have complete. The logic in your case would be to update label1
with the final result.
Pretty basic way:
Pseudocode
bool thread1Complete = false
bool thread2Complete = false
StartThread1()
StartThread2()
Thread1CompletedEventHandler():
thread1Complete = true
UpdateUI()
Thread2CompletedEventHandler():
thread2Complete = true
UpdateUI()
UpdateUI():
if thread1Complete and thread2Complete then
SetStatusText()
Details will depend on your threading implementation. If you use BackgroundWorker then you won't need to use Control.Invoke() to update your status control, but if you call the ThreadXCompletedEventHandler() methods from your threads, then you will need to use Control.Invoke().
If you're targeting .NET 4, you may want to look into Tasks.
You can use Control.Invoke to invoke methods on the main thread. The delegate can safely interact with the controls. See this for details.
You can use Thread.Join()
to wait for a thread to finish, blocking the current thread.
精彩评论