C# 控件出现意外的块条件。调用
下面的代码是一个简化的概念证明。 在windows窗体应用程序中,有一个FormClosing事件处理程序来执行某些清理。应用程序启动一些线程,这些线程使用Control.Invoke在表单上写入。我知道我可以使用Control.BeginInvoke,但我想更好地了解发生了什么,并找到另一种解决方案C# 控件出现意外的块条件。调用,c#,multithreading,winforms,C#,Multithreading,Winforms,下面的代码是一个简化的概念证明。 在windows窗体应用程序中,有一个FormClosing事件处理程序来执行某些清理。应用程序启动一些线程,这些线程使用Control.Invoke在表单上写入。我知道我可以使用Control.BeginInvoke,但我想更好地了解发生了什么,并找到另一种解决方案 List<Thread> activeThreadlist; volatile bool goOnPolling = true; private void Form1_FormClos
List<Thread> activeThreadlist;
volatile bool goOnPolling = true;
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
goOnPolling = false;
Thread.Sleep(1000);
foreach (Thread element in activeThreadlist)
if (element.IsAlive)
element.Abort();
}
在大约50%的情况下,当窗体关闭时,线程会阻塞Control.Invoke,这样它们就不会在睡眠时间终止,并调用Abort。我认为在调用Invoke之前检查标志goOnPolling在99.999%的情况下就足够了,但我错了。正如代码中所述,线程会进行长时间的细化(至少100ms),因此我预计goOnPolling可能会在执行过程中发生变化。为什么我错了?是否有另一种不重复使用BeginInvoke创建额外线程的简单解决方案
更新
看完评论后,我意识到标题错了。我最初编写了死锁,但这只是一个意外的(对我来说)块条件。一开始,我不明白为什么我的线程在等待它们的终止1000毫秒后仍然活着,所以我设置了一个中止来找出答案。我完全误解了调用和开始调用之间的区别,感谢您的澄清
@乔恩B
我同意break比continue更合适,但是代码在while(goOnPolling)块中,因此我只能节省一些cpu周期,仅此而已
你知道为什么在调用的早期阶段,goOnPolling经常发生变化吗?如果我进行长时间的细化,大部分时间都应该在那里进行 我们知道这些其他线程希望通过
调用
进入UI线程,我们知道您正在睡眠
中捆绑UI
线程
这可能是Application.DoEvents
在这里最不坏的选项之一:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
goOnPolling = false;
for(int i=0;i<10;i++)
{
Application.DoEvents();
Thread.Sleep(50);
}
//foreach (Thread element in activeThreadlist)
// if (element.IsAlive)
// element.Abort();
}
private void Form1\u FormClosing(对象发送方,FormClosingEventArgs e)
{
goOnPolling=假;
对于(int i=0;iBeginInvoke
不应该创建额外的线程,它只是对现有UI线程上的工作进行排队。创建新线程将完全违背BeginInvoke
的设计目的。你确定你的最后一句话吗?据我所知,Invoke
和BeginInvoke
执行在UI线程中,只有Invoke
会在返回前阻塞。即Invoke
=BeginInvoke
+等待执行。您可能会与delegate
Invoke
/BeginInvoke
混淆,请参阅。使用控件.Invoke
的唯一原因是当您需要调用的操作在执行前完成时继续调用线程。我是100%肯定的。Invoke
将消息循环上的执行排队,然后等待它完成。BeginInvoke
执行完全相同的操作,但在完成之前不会阻塞。这可能是死锁的来源。您的UI线程正在等待子线程,而子线程线程正在等待UI完成。@BradleyUffner“你确定…”是针对OP的。@Filippo同样,你可能永远不应该调用线程。中止.99%(甚至更高)通常,当您看到线程.Abort
时,您正在做一些非常错误的事情。它会使应用程序处于无法预测的状态,最终导致各种疯狂的错误。请参阅
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
goOnPolling = false;
for(int i=0;i<10;i++)
{
Application.DoEvents();
Thread.Sleep(50);
}
//foreach (Thread element in activeThreadlist)
// if (element.IsAlive)
// element.Abort();
}