开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜