Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C向FormClosing事件添加代码将禁用MdiParent上的X_C#_.net_Multithreading_Formclosing - Fatal编程技术网

C# C向FormClosing事件添加代码将禁用MdiParent上的X

C# C向FormClosing事件添加代码将禁用MdiParent上的X,c#,.net,multithreading,formclosing,C#,.net,Multithreading,Formclosing,我有两个后台线程和一个线程来处理WinForms应用程序上运行的最小化。当程序关闭时,我使用这个方法 private void MyForm_Closing(object sender, FormClosingEventArgs e) { if(labelsUpdaterThread.IsAlive == true) labelsUpdaterThread.Abort(); if(printNotifyThread.IsAlive

我有两个后台线程和一个线程来处理WinForms应用程序上运行的最小化。当程序关闭时,我使用这个方法

private void MyForm_Closing(object sender, FormClosingEventArgs e)
    {
        if(labelsUpdaterThread.IsAlive == true)
            labelsUpdaterThread.Abort();
        if(printNotifyThread.IsAlive == true)
            printNotifyThread.Abort();
        if(minimizeThread.IsAlive == true)
            minimizeThread.Abort();
    }
labelsUpdaterThread和printNotifyThread始终运行。正如您可能猜到的,MinimizeThread仅在父窗体最小化时运行。我的问题是:

在上述方法中调用thread.abort方法时,父窗体右上角的X不会执行任何操作。单击它没有效果

在我上面的方法中未调用thread.abort方法时,关闭MdiParent有时会引发异常,因为线程仍在尝试访问MdiParent上不再可用的资源,即使它们是后台线程


我不确定为什么会发生这种情况,对我来说没有多大意义。提前感谢您的帮助

中止调用可能引发异常。在调用abort之前,确保指针有效且线程仍然有效


并且,在visual studio中,打开调试\异常。。。并在“抛出”列中为所有异常设置检查,以便在出现问题时查看

中止调用可能引发异常。在调用abort之前,确保指针有效且线程仍然有效


并且,在visual studio中,打开调试\异常。。。并在“抛出”列中为所有异常设置检查,以便在出现问题时查看

首先,删除对的调用。中止并不再使用它们。决不能通过调用中止来终止线程。它基本上会使你的线程崩溃,并且不会给它一个适当释放任何资源或释放任何系统句柄的机会。相反,创建一个ManualResetEvent并在线程中检查它。设置事件后,它们应终止

螺纹1

while( ! _stopEvent.WaitOne(0) )
{
  ...do my thready work

}
最后

private void MyForm_Closing(object sender, FormClosingEventArgs e)
{
  _stopEvent.Set();
  labelsUpdaterThread.Join();
  ...
}

如果您不关心线程是否在应用程序存在时正确终止,只需设置IsBackground=true,当应用程序退出时,线程将自动终止。

首先,删除对.Abort的调用,并不再使用它们。决不能通过调用中止来终止线程。它基本上会使你的线程崩溃,并且不会给它一个适当释放任何资源或释放任何系统句柄的机会。相反,创建一个ManualResetEvent并在线程中检查它。设置事件后,它们应终止

螺纹1

while( ! _stopEvent.WaitOne(0) )
{
  ...do my thready work

}
最后

private void MyForm_Closing(object sender, FormClosingEventArgs e)
{
  _stopEvent.Set();
  labelsUpdaterThread.Join();
  ...
}
如果您不关心线程是否在应用程序存在时正确终止,只需设置IsBackground=true,当应用程序退出时,它们将自动终止。

我同意,您不应该调用Thread.Abort,这是处理同步的可怕方式

此外,您在这里有一个可怕的关注点分离。线程不应该直接访问表单中的资源。在这两者之间应该有某种抽象/共享状态,线程和表单的双方都可以修改和读取这种状态,因此请确保实例线程是安全的

也就是说,如果您不能进行这些更改,那么在Close方法中,调用另一个线程中的Thread.Abort方法,每个方法周围都有一个try/catch语句。至少在某个地方记录错误

在另一个线程上执行对Thread.Abort的调用时,您不会阻止UI线程,因为对Thread.Abort的调用不能保证是即时的,阻止UI线程将导致X变灰,而UI线程无法处理Windows消息。这也有助于引导您更好地分离关注点

但是,您应该将表单和线程之间共享的资源抽象出来,并提供适当的取消机制

如果将资源抽象为共享状态的类,则窗体不必在关闭时执行任何操作,线程调用堆栈具有对具有状态的对象的引用,然后可以在这些线程上调用abort,而无需担心窗体和共享任何内容的线程

然后,您可以引入适当的协作取消机制(如果您可以使用的话)。

我同意您不应该调用Thread.Abort,这是处理同步的可怕方式

此外,您在这里有一个可怕的关注点分离。线程不应该直接访问表单中的资源。在这两者之间应该有某种抽象/共享状态,线程和表单的双方都可以修改和读取这种状态,因此请确保实例线程是安全的

也就是说,如果您不能进行这些更改,那么在Close方法中,调用另一个线程中的Thread.Abort方法,每个方法周围都有一个try/catch语句。至少在某个地方记录错误

在另一个线程上执行对Thread.Abort的调用时,您不会阻止UI线程,因为对Thread.Abort的调用不会被阻止 保证是即时的,并且阻止UI线程将导致X变灰,而UI线程无法处理Windows消息。这也有助于引导您更好地分离关注点

但是,您应该将表单和线程之间共享的资源抽象出来,并提供适当的取消机制

如果将资源抽象为共享状态的类,则窗体不必在关闭时执行任何操作,线程调用堆栈具有对具有状态的对象的引用,然后可以在这些线程上调用abort,而无需担心窗体和共享任何内容的线程



从那里,您可以引入适当的协作取消机制(如果您可以使用的话)。

更改了异常,它在第一个线程上抛出此异常。中止。在线程5736上运行的用户代码试图中止线程5692。如果中止的线程处于修改全局状态或使用本地资源的操作的中间,则可能导致损坏的状态或资源泄漏。强烈建议中止当前正在运行的线程以外的线程。那么,当后台线程正在运行时,关闭WinForms应用程序的正确行为是什么?@CODe:更安全的方法是设置应用程序正在关闭的标志,确保所有背景线程定期检查,并在看到设置后完成。然后在线程上进行连接,等待线程关闭。在GUI应用程序中运行线程时,我倾向于选择后台工作人员,但这更需要返工。@jdv:您是否建议采用类似于Paul Alexander回答的方法?我试过了,不幸的是没用。它只是冻结了整个应用程序。@CODe:我倾向于同意调用Thread.Abort是个坏主意。甚至通常使用原始的.net线程。但我也觉得你从犯错误中学到了更多,而不是听别人说。您的线程是否定期检查现在是否是关机时间?更改了异常,它在第一个线程上抛出此异常。中止。在线程5736上运行的用户代码试图中止线程5692。如果中止的线程处于修改全局状态或使用本地资源的操作的中间,则可能导致损坏的状态或资源泄漏。强烈建议中止当前正在运行的线程以外的线程。那么,当后台线程正在运行时,关闭WinForms应用程序的正确行为是什么?@CODe:更安全的方法是设置应用程序正在关闭的标志,确保所有背景线程定期检查,并在看到设置后完成。然后在线程上进行连接,等待线程关闭。在GUI应用程序中运行线程时,我倾向于选择后台工作人员,但这更需要返工。@jdv:您是否建议采用类似于Paul Alexander回答的方法?我试过了,不幸的是没用。它只是冻结了整个应用程序。@CODe:我倾向于同意调用Thread.Abort是个坏主意。甚至通常使用原始的.net线程。但我也觉得你从犯错误中学到了更多,而不是听别人说。你的线程是否定期检查现在是否是关机时间?如果你没有执行任何可能取消关闭事件的验证,你应该使用FormClose而不是FormClose。请不要编辑问题中的示例代码。这可能会导致前面给出的答案看起来不正确。@unholy:FormClosed发生在表单关闭之后。然后,我的应用程序抛出异常,因为它们试图访问关闭线程上的资源。@jdv:很抱歉,但老实说,您的答案一开始似乎并不正确。但我确实理解保持这个问题不变的必要性。我以后不会再改了。@Everyone:希望你能在这里撞一下,还是没有办法!:如果您没有执行任何可能取消关闭事件的验证,则应使用FormClosed而不是FormClosed。请不要编辑问题中的示例代码。这可能会导致前面给出的答案看起来不正确。@unholy:FormClosed发生在表单关闭之后。然后,我的应用程序抛出异常,因为它们试图访问关闭线程上的资源。@jdv:很抱歉,但老实说,您的答案一开始似乎并不正确。但我确实理解保持这个问题不变的必要性。我以后不会再改了。@Everyone:希望你能在这里撞一下,还是没有办法!:执行上述操作,然后单击X现在可以锁定整个应用程序,而不会像以前那样引发异常。它只是冻结了/只有当线程没有正确监视_stopEvent时,它才会锁定应用程序。它们应该定期轮询以查看是否设置了事件,如果设置了,则从主线程函数返回。你
可能需要阅读线程编程的相关知识,以便更好地理解其含义。Windows上的并发编程是一个很好的资源。此外,为线程设置IsBackground=true将允许.NET在应用程序退出时自动终止它们-不会锁定应用程序。我不确定在尝试您的解决方案时发生了什么。线程有5秒的等待时间,还有一段时间_stopEvent.WaitOne0和my线程都是后台线程,程序仍然冻结。顺便说一下,谢谢你的阅读参考,我会顺便去巴恩斯和诺布尔看看我是否能找到一个,或者至少是类似的东西。执行上述操作,然后单击X现在可以锁定我的整个应用程序,而不会像以前一样引发异常。它只是冻结了/只有当线程没有正确监视_stopEvent时,它才会锁定应用程序。它们应该定期轮询以查看是否设置了事件,如果设置了,则从主线程函数返回。您可能需要阅读线程编程,以便更好地理解其含义。Windows上的并发编程是一个很好的资源。此外,为线程设置IsBackground=true将允许.NET在应用程序退出时自动终止它们-不会锁定应用程序。我不确定在尝试您的解决方案时发生了什么。线程有5秒的等待时间,还有一段时间_stopEvent.WaitOne0和my线程都是后台线程,程序仍然冻结。顺便说一下,谢谢你的阅读参考,我会顺便拜访巴恩斯和诺布尔,看看是否能找到一个,或者至少是类似的。请原谅我的知识不足,调用线程如何。使用try/catch从另一个线程中止对我的案例有帮助吗?它与我目前使用的try/catch有什么不同?非常感谢您的帮助。@CODe:在另一个线程上调用Thread.Abort时,您并没有阻塞UI线程,而这正是问题的根源所在X被禁用。我已经更新了我的答案来反映这一点。谢谢!新线程工作。现在,我对这个快速解决方案很满意,但我将在接下来的几天里推动您所讨论的抽象。不幸的是,我的雇主只让我每天工作一定的时间;我非常感谢你的贡献!请原谅我的知识不足,调用Thread.Abort从另一个线程使用try/catch如何帮助我的案例?它与我目前使用的try/catch有什么不同?非常感谢您的帮助。@CODe:在另一个线程上调用Thread.Abort时,您并没有阻塞UI线程,而这正是问题的根源所在X被禁用。我已经更新了我的答案来反映这一点。谢谢!新线程工作。现在,我对这个快速解决方案很满意,但我将在接下来的几天里推动您所讨论的抽象。不幸的是,我的雇主只让我每天工作一定的时间;我非常感谢你的贡献!