我有一个GUI界面,它有一个开始和一个取消按钮。启动后,作为GUI线程的主线程正在创建第二个线程,它将执行实际工作。当按下取消按钮时,它所做的就是设置一个布尔值,告诉工作线程停止工作并结束。问题是主GUI线程仍然卡住,即使我确信工作线程已完成它正在做的事情。那是为什么?
以下是一些代码:
private Thread workerThread;
private SomeClass fs;
private void buttonSearch_Click(object sender, EventArgs e)
{
//do some initializations
fs = new SomeClass();
workerThread = new Thread(fs.WorkMethod);
workerThread.Start();
}
private void buttonCancel_Click(object sender, EventArgs e)
{
fs.StopWork();
workerThread.Join();
}
inside SomeClass:
private bool keepWorking;
public void StopWork()
{
keepWorking= false;
}
public void WorkMethod()
{
if (keepWorking)
{
//do some stuff with recursion
}
}
有人知道为什么在调用join之后主线程不会唤醒? 我也尝试过调试,看看如果我手动将keepWorking变量更改为false并且方法确实达到了它的结果会发生什么。
答案 0 :(得分:4)
你的WorkMethod
在那里调用Invoke
调用一个委托在UI线程上运行然后阻塞直到它完成。由于您的UI线程当前在等待后台线程的Join
调用时阻塞,因此UI线程无法调用该委托。
现在你们两个线程都在等待另一个线程,并且没有进展。这被称为“死锁”。
此外,keepWorking
应标记为volatile
,因为它是从多个线程访问的;因为它是后台线程可以在主线程更改它之后很长一段时间访问该变量的过时/缓存值。将其标记为volatile
会阻止运行时进行此类优化。
这里的解决方案是不通过调用Join
来阻止UI线程。如果你需要在后台线程结束时执行某些代码,那么当线程完成而不是同步阻塞时,你需要异步触发该代码。