除了调用线程之外,我如何才能等待线程完成运行.Join()

本文关键字:线程 等待 Join 运行 调用 | 更新日期: 2023-09-27 17:59:40

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

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

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

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

除了调用线程之外,我如何才能等待线程完成运行.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的调用
  • 每当从不是UI线程的线程访问窗体或控件方法和属性时,请始终记住选中InvokeRequired并使用control.Invoke(/*..*/)

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

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