我正在使用多线程编写应用程序。该应用程序基本上有一个UI和一个线程在后台做一些工作并更新UI。当我关闭表单时,在formclosing事件中,我通知工作线程停止。然而,由于某些原因,它阻止了,我不知道是什么导致它阻止。下面是我的问题的简化代码,我的实际代码更复杂。
namespace CmdTest
{
public partial class Form1 : Form
{
Thread _workerThread;
static object _lock;
static bool _stopFlag;
public Form1()
{
_lock = new object();
_stopFlag = false;
_workerThread = new Thread(new ThreadStart(ThreadDoWork));
InitializeComponent();
_workerThread.Start();
}
delegate void UpdateUI();
public void UpdateUICallback()
{
//Doing stupid things
int i = 0;
while (i < 10000)
{
i++;
}
}
public void ThreadDoWork()
{
if (this.InvokeRequired)
{
UpdateUI updateUI = new UpdateUI(UpdateUICallback);
while (true)
{
//telling the UI thread to update UI.
this.Invoke(updateUI);
lock (_lock)
{
if (_stopFlag)
return;
}
}
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
//tell the worker thread to terminate.
lock (_lock)
{
_stopFlag = true;
Monitor.Pulse(_lock);
}
while (!_workerThread.Join(0))
{
}
}
}
}
问题是如果我使用
lock (_lock)
{
_stopFlag = true;
Monitor.Pulse(_lock);
}
要在按钮事件中停止工作线程,工作线程将停止但不在窗体关闭事件中。任何帮助,将不胜感激。感谢。
答案 0 :(得分:3)
您的FormClosing
事件在方法结束之前等待后台线程关闭。请注意,它将在UI线程中运行。
你的后台线程在循环中调用UI线程中的方法,因为你使用Invoke
而不是BeginInvoke
,它正在等待该方法完成后再继续。
UI正在运行结束事件,坐在那里什么都不做。由于它什么都不做,它无法处理消息循环中的任何其他事件,包括后台线程正在等待的一种方法。
两个线程都在彼此等待,并且没有进行任何有效的工作。这是死锁的定义。它会永远这样。
请注意,这是竞争条件;如果你足够幸运,在给定的Invoke
调用完成之后和下一次检查标志之前关闭表单(这很难;它在这些操作之间花费的时间很少)那么你的程序就不会死锁
至于如何解决它;这很难说。整个例子有点人为。
也许您根本不需要从后台工作者调用UI;如果你实际上没有做UI工作,你可能不应该这样做。
你真的需要等待后台工作人员在你的结算处理程序中完成吗?你可以这样做,但通常你不会这样做。