C# 控件出现意外的块条件。调用

C# 控件出现意外的块条件。调用,c#,multithreading,winforms,C#,Multithreading,Winforms,下面的代码是一个简化的概念证明。 在windows窗体应用程序中,有一个FormClosing事件处理程序来执行某些清理。应用程序启动一些线程,这些线程使用Control.Invoke在表单上写入。我知道我可以使用Control.BeginInvoke,但我想更好地了解发生了什么,并找到另一种解决方案 List<Thread> activeThreadlist; volatile bool goOnPolling = true; private void Form1_FormClos

下面的代码是一个简化的概念证明。 在windows窗体应用程序中,有一个FormClosing事件处理程序来执行某些清理。应用程序启动一些线程,这些线程使用Control.Invoke在表单上写入。我知道我可以使用Control.BeginInvoke,但我想更好地了解发生了什么,并找到另一种解决方案

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

我同意breakcontinue更合适,但是代码在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;i
BeginInvoke
不应该创建额外的线程,它只是对现有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();
}