一尘不染

NET中如何等待线程完成?

c#

我以前从未真正在C#中使用过线程,在C#中,我需要有两个线程以及主UI线程。基本上,我有以下几点。

public void StartTheActions()
{
  //Starting thread 1....
  Thread t1 = new Thread(new ThreadStart(action1));
  t1.Start();

  // Now, I want for the main thread (which is calling `StartTheActions` method) 
  // to wait for `t1` to finish. I've created an event in `action1` for this. 
  // The I wish `t2` to start...

  Thread t2 = new Thread(new ThreadStart(action2));
  t2.Start();
}

因此,本质上,我的问题是如何让一个线程等待另一个线程完成。做这个的最好方式是什么?


阅读 330

收藏
2020-05-19

共1个答案

一尘不染

我可以看到5个可用选项:

1. Thread.Join

和米奇的答案一样。但这会阻塞您的UI线程,但是您会为您内置一个超时。


2.使用 WaitHandle

ManualResetEventWaitHandle克里斯蒂娜建议的。

需要注意的一件事是,如果您要等待多个线程,WaitHandle.WaitAll()则默认情况下将不起作用,因为它需要一个MTA线程。您可以通过用Main()方法标记您的方法来解决此问题MTAThread-但这会阻塞您的消息泵,因此,根据我的阅读,不建议这样做。


3.触发事件

请参阅乔恩·斯基特(Jon
Skeet)的
有关事件和多线程的页面,事件可能在if和之间取消订阅EventName(this,EventArgs.Empty)-这是我以前发生过的事情。

(希望这些编译,我没有尝试过)

public class Form1 : Form
{
    int _count;

    void ButtonClick(object sender, EventArgs e)
    {
        ThreadWorker worker = new ThreadWorker();
        worker.ThreadDone += HandleThreadDone;

        Thread thread1 = new Thread(worker.Run);
        thread1.Start();

        _count = 1;
    }

    void HandleThreadDone(object sender, EventArgs e)
    {
        // You should get the idea this is just an example
        if (_count == 1)
        {
            ThreadWorker worker = new ThreadWorker();
            worker.ThreadDone += HandleThreadDone;

            Thread thread2 = new Thread(worker.Run);
            thread2.Start();

            _count++;
        }
    }

    class ThreadWorker
    {
        public event EventHandler ThreadDone;

        public void Run()
        {
            // Do a task

            if (ThreadDone != null)
                ThreadDone(this, EventArgs.Empty);
        }
    }
}

4.使用委托

public class Form1 : Form
{
    int _count;

    void ButtonClick(object sender, EventArgs e)
    {
        ThreadWorker worker = new ThreadWorker();

        Thread thread1 = new Thread(worker.Run);
        thread1.Start(HandleThreadDone);

        _count = 1;
    }

    void HandleThreadDone()
    {
        // As before - just a simple example
        if (_count == 1)
        {
            ThreadWorker worker = new ThreadWorker();

            Thread thread2 = new Thread(worker.Run);
            thread2.Start(HandleThreadDone);

            _count++;
        }
    }

    class ThreadWorker
    {
        // Switch to your favourite Action<T> or Func<T>
        public void Run(object state)
        {
            // Do a task

            Action completeAction = (Action)state;
            completeAction.Invoke();
        }
    }
}

如果您确实使用_count方法,则可能会(为了安全起见)使用以下方法增加它

Interlocked.Increment(ref _count)

我很想知道使用委托和事件进行线程通知之间的区别,我唯一知道的区别是事件是同步调用的。


5.异步执行

这个问题的答案非常清楚地说明了使用此方法的选择。


代表/事件在错误的线程上

事件/委托的处理方式将意味着您的事件处理程序 方法 位于thread1 / thread2 而非主UI线程上
,因此您需要在HandleThreadDone方法的顶部重新切换:

// Delegate example
if (InvokeRequired)
{
    Invoke(new Action(HandleThreadDone));
    return;
}
2020-05-19