除了通过调用thread.Join()之外,我怎么能等待一个线程完成运行?

我正在开发一个项目,其中从库中可用的应用程序调用方法。

我在按钮点击事件中有以下代码:

Thread thread = new Thread(new ThreadStart(AddPics)); thread.Priority = ThreadPriority.Highest; thread.Start(); execute(); 

但是在运行示例时,执行点总是会移动到执行。 如何使程序首先执行AddPics方法。 我已经尝试过thread.Join()并且它有效,但我想知道是否还有其他方法可以实现这一点。

您可以使用JoinAutoResetEvent等到添加图片线程完成, 但您不应该使用后面的答案解释。

使用AutoResetEvent替代Join可以获得相同的结果; 它允许您设置阻塞通知,因此在调用execute()方法之前阻塞,并且仅在AddPics线程完成其作业时继续:

 private AutoResetEvent _finishAddPicsNotifier = new AutoResetEvent(false); private void OnMyButton_Click(object sender, EventArgs e) { //..... new Thread(AddPics) { Priority = ThreadPriority.Highest, IsBackground = true, //will explain later }.Start(); _finishAddPicsNotifier.WaitOne();//this will block until receive a signal to proceed execute();//this method will only be called after the AddPics method finished /..... } private void AddPics() { try{ //....... } finally{ _finishAddPicsNotifier.Set();//when finished adding the pictures, allow the waiting method to proceed } } 

注意:设置IsBackground = true表示该线程是后台线程,因此不会阻止应用程序终止。 在这里阅读更多关于后台线程

问题:

  • 由于您使用按钮单击以运行该线程,您应该添加一些机制以防止多次单击同时多次运行代码。
  • 您还在调用Join()_finishAddPicsNotifier.WaitOne()时阻止UI线程。

要解决所有这些问题 ,一个好的设计是定义OnFinishAddingPictures方法并在完成添加图像时调用它,在这个新方法调用execute() ,你还应该从按钮点击中删除之前的execute()调用:

 private readonly object _oneAddPicturesLocker = new object(); private void OnMyButton_Click(object sender, EventArgs e) { //..... new Thread(AddPics) { Priority = ThreadPriority.Highest, IsBackground = true, }.Start(); } private void AddPics() { if (Monitor.TryEnter(_oneAddPicturesLocker)) { //we only can proceed if no other AddPics are running. try { //..... OnFinishAddingPictures(); } finally { Monitor.Exit(_oneAddPicturesLocker); } } } private void OnFinishAddingPictures() { execute(); } 

注意:

  • 我们使用这种机制摆脱阻塞。
  • 我们确信AddPics只执行一次对AddPics调用。
  • 每当从非线程的线程访问表单或控件方法和属性时,请务必检查InvokeRequired并使用control.Invoke(/*..*/)

我假设您的主要观点是在使用AddPics的线程运行时具有响应式UI? 如果是这样,那么您可以将此构造用于WinForms:

 while (thread.IsAlive) System.Windows.Forms.Application.DoEvents();