【发布时间】:2013-09-03 18:18:04
【问题描述】:
我有许多线程可以调用来更新 GUI 的代码:
MethodInvoker del = () => { lblInfo.Text = tmp; };
lblInfo.BeginInvoke(del);
(lblInfo由GUI线程创建)
我也有这个方法在 GUI 线程执行的按钮单击时调用:
public void Stop()
{
isStopping = true;
crawler.Join();
foreach (Thread t in txtWorkers)
{
t.Join();
}
indexer.Join();
lblStatus.Text = "Stopped";
lblInfo.Text = "";
}
1 次超过 100 次运行程序在单击停止按钮时死锁。当我看到死锁时我没有调试,所以我不能确定各种线程的状态,但我几乎可以肯定我加入的所有线程最终都会到达他们检查的点
isStopping 值并终止。这使我认为BeginInvoke 可能存在问题,但无法真正找到它。它应该是异步的,因此调用它的线程(爬虫和索引器)不应该阻塞。如果 GUI 线程正在执行 Stop() 并且还必须执行来自 BeginInvoke 的调用,会发生什么情况?这可能是问题吗?我正在加入的线程有什么我看不到的吗?
编辑: 建议更改后的代码是什么样的:
public void Stop()
{
/*
...disable GUI
*/
isStopping = true; // Declared as volatile
lblStatus.Text = "Stopping...";
// Creating a thread that will wait for other threads to terminate
Task.Factory.StartNew(() =>
{
crawler.Join();
foreach (Thread t in txtWorkers)
{
t.Join();
}
indexer.Join();
// Adjust UI now that all threads are terminated
MethodInvoker del = () =>
{
/*
...enable GUI
*/
lblStatus.Text = "Not Running";
isStopping = false;
};
lblStatus.BeginInvoke(del);
});
}
它似乎在工作,我希望僵局已经过去了......
【问题讨论】:
-
你试过
lblInfo.Invoke(del)吗? -
@AlessandroD'Andria 遇到这样一个罕见的问题,我不能只是因为它工作过一次而感到高兴,而且在我看来,使用调用确实会导致死锁
-
就像 Jon Skeet 所说,不要在 GUI 事件处理程序中调用阻塞操作。
标签: c# multithreading .net-4.5 begininvoke