除了调用线程之外,我如何才能等待线程完成运行.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
或AutoResetEvent
等待添加图片线程完成,但您不应该使用这两种方法,如稍后的答案所述
使用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();