【问题标题】:Substitute for async/await when C# form is closing since await never returns? [duplicate]当 C# 表单关闭时替代 async/await 因为 await 永远不会返回? [复制]
【发布时间】:2015-06-19 19:19:45
【问题描述】:

我有一个启动其他进程的 C# Windows 窗体应用程序。当表单关闭时,我需要关闭这些进程并确保它们已经消失,这样它们就不会像僵尸进程一样徘徊。我的策略是通过套接字桥向进程发送关闭命令,然后等待它们正常关闭。但是 3 秒后,如果它们还在,我会强制关闭它们(杀死它们)。

最初我使用了表单的 Closing 事件中的 await Task.Delay(3000) 指令。然而这并没有奏效。当 await Task.Delay(3000) 语句试图返回时,主线程已经消失,因此如果子进程仍在 附近,该语句之后的代码会强制关闭子进程从未执行过。为了解决这个问题,我将 await Task.Delay(3000) 更改为普通的 Thread.Sleep(3000) 语句。现在执行 Thread.Sleep(3000) 之后的代码,因为线程从未像以前那样切换。

但是,在 3 秒内我的应用似乎没有响应。我可以使用什么技术来确保 3 秒等待后的代码确实执行,而不会阻塞主 UI 线程?

【问题讨论】:

  • 我实际上不认为这是重复的,因为 OP 在 FormClosing 中尝试完成的内容不同,因此,他可以考虑不同的选择。
  • 他们都在FormClosing中调用异步方法
  • 如果您可以访问子线程作为任务,您可以在主线程中执行以下操作 Task.WaitAll(tasks,3000); //任务是你的子线程使用 WaitAll 甚至你可以使用 CancellationToken 来取消你的线程
  • @Yuval:不同之处在于,在这种情况下,他并没有像您链接的其他问题那样试图阻止表单关闭。这改变了他的问题的潜在答案。
  • @Yuval:表单关闭并不意味着进程将自动关闭。只要还有一个前台线程在运行,如果我在 FormClosing 中启动一个前台线程,那么该进程就会保持活动状态。如果我是那个遗漏了显而易见的人,请原谅我。

标签: c# multithreading async-await task-parallel-library


【解决方案1】:

在表单的关闭事件中,您可以启动一个新线程,它所做的只是:

  • 睡 3 秒
  • 然后杀死进程

因为睡眠发生在那个单独的线程上,所以您不必担心冻结 UI。而且因为您的线程不是后台线程,所以它在休眠时不会消失:)

编辑:

我运行了这个简单的测试来证明我的观点。即使在我关闭表单并且 FormClosing 事件完成之后,我的线程仍在运行,并且应用程序只有在线程唤醒并完成其工作后才真正关闭。我疯了吗?

  private void Form1_FormClosing(object sender, FormClosingEventArgs e)
  {
     Thread t = new Thread(() =>
     {
        Thread.Sleep(10000);
        Debug.WriteLine("I am still alive!!!  So I can still kill the processes here");
        // After this point, the process shuts down, because this was the last thread running.
     });
     t.Start();

     // at this point, the form will close, but the process is still alive as long as thread `t` is alive.
  }

编辑 2:

对于任何想对此投反对票的人:至少拿我的小sn-p代码尝试一下,然后再假设它不起作用。如果它完全失败,请给我投票并让我知道,以便我可以从中学习。

但就目前而言,至少我尽了自己的一份力量:我实际测试了这个,它确实有效。

【讨论】:

  • 他已经这样做了,但他不希望他的主应用程序冻结
  • @Dan Hunex:不,他没有。他在 UI 线程中执行了睡眠。我建议他在单独的线程上进行睡眠。
  • 除非创建的线程是Foreground,否则这将无效。
  • 如果您可以访问子线程作为任务,您可以在主线程中执行以下操作 Task.WaitAll(tasks,3000); //任务是你的子线程使用 WaitAll 甚至你可以使用 CancellationToken 来取消你的线程
  • @Yuval:我执行了一个简单的测试,您可以在我的编辑中看到。我的例子有什么问题?
猜你喜欢
  • 2012-05-07
  • 2017-05-08
  • 2017-05-25
  • 2019-05-30
  • 2018-05-16
  • 2013-02-27
  • 2016-12-12
  • 1970-01-01
  • 2020-09-21
相关资源
最近更新 更多