【问题标题】:C# Program freezes in for loopC# 程序在 for 循环中冻结
【发布时间】:2015-06-05 03:47:26
【问题描述】:

我这里有这段代码,它启动一个进程等待 8 秒,然后再次杀死它。

for (int i = 0; i < 20; i++)
{
    Process pro = new Process();
    pro.StartInfo.FileName = @"C:\Program Files (x86)\Mozilla Firefox\firefox.exe";
    pro.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
    pro.Start();

    Thread.Sleep(8000);

    try
    {
        pro.Kill();
        Thread.Sleep(1000);
    }
    catch
    {
        return;
    }
}

当我在调试模式或直接从 .exe 运行应用程序时,它成功启动并终止了进程,但它被冻结了。我不能移动它的窗口或点击其他按钮..

【问题讨论】:

  • 这是因为 Win 表单是单线程的,并且没有退出的紧密循环使系统没有空间重新绘制表单或响应鼠标事件。
  • 有什么办法可以摆脱这种情况吗?
  • 为了不阻塞 UI 线程,你需要异步而不是同步地完成你的工作。
  • @Jeremy 小心,您可以轻松在 win forms 应用程序中使用线程,它只是 UI 线程是他可能的单个线程阻止。
  • 我应该说“默认情况下”是单线程的。布拉德利是正确的

标签: c# freeze


【解决方案1】:

它被冻结了。我无法移动它的窗口或点击其他按钮。

没错。你说让线程休眠。

人们似乎有一个奇怪的想法,即按下按钮时运行代码是靠魔法发生的。它不是靠魔法发生的。发生这种情况是因为线程运行的代码处理来自操作系统的“单击按钮”消息。如果你让一个线程进入睡眠状态,它就会停止处理这些消息,因为它处于睡眠状态。

让线程休眠在 99% 的情况下都是完全错误的做法,所以不要这样做。

在 C# 5 中正确的做法是创建您的方法 async,然后执行 await Task.Delay(whatever)。或者,创建一个在几秒后计时的计时器。在滴答声处理事件中,关闭计时器并在那里执行您的逻辑。

【讨论】:

  • 我有一个在后台运行的 .NET 应用程序,它必须以最轻松的方式执行其操作,并且对系统的影响最小。我已经将消耗资源的调用与Thread.Sleep(1) 调用交错。您认为这是可以接受的,还是有更好的方法来控制 .NET 中的资源使用?
  • @LucaCremonesi:我绝对不会这样做,而且我不知道您为什么认为这会帮助您实现目标。您的精确、可衡量的目标是什么?您收集了哪些经验证据表明这种技术可以实现您的目标?你认为Sleep(1) 有什么好处,比如Yield
  • 或者,如果您希望所有其他非空闲线程优先,那么简单地将线程的优先级设置为低于平均水平有什么问题?
  • @LucaCremonesi:我经常听到人们说他们希望 CPU 利用率低,我真的对此感到困惑。我为那个 CPU 付了很多钱,我希望它被使用!如果您的 CPU 一直以 5% 的容量运行,那么您肯定多付了 20 倍。
  • @NumLock:实际上 System.Threading.Timer 的回调 可重入的,因此在实现方法时必须考虑到这一点(来自文档:“回调可以在两个线程池线程上同时执行...")。
【解决方案2】:

嗯,我最初的猜测是你在你的 UI 线程上做这一切。由于您使 UI 线程休眠,您的应用程序将被冻结。

显而易见的解决方案是在新线程中执行此操作。

正如 Servy 所说,这不是一个好主意。您可以使用 Timer (https://msdn.microsoft.com/en-us/library/system.timers.timer%28v=vs.110%29.aspx) 来进行等待,而不是阻塞 UI 线程。

【讨论】:

  • 创建一个新线程只是为了让它在 100% 的时间里无所事事是一个糟糕的主意。
  • 异步处理好东西意味着你有一个新线程,不是吗?更新了我的答案,建议使用 Timer。
  • @Robert:不,异步并不意味着并发。并发只是一种异步。如果您决定在等待鸡蛋煮熟时将吐司放入烤面包机,那么您正在使用异步。如果您决定雇用两名厨师,一名煮鸡蛋,一名煮吐司,那么您将同时使用异步和并发。你觉得哪个便宜?
  • @Robert 这是一个稍微长一点的解释:stackoverflow.com/a/17279822/1159478,这是另一个:stackoverflow.com/questions/23833255/…
  • 我可能在这里走错了路,但我需要一些不是我的 UI 线程的东西(线程?)来完成我的异步工作。我可以请一个厨师来做我的鸡蛋和我的烤面包机,但如果我是服务员,我就没有时间了。
【解决方案3】:

应用程序的主线程是一个循环,它不断地从 Windows 消息队列中查看消息。这就像协作多线程——如果你不明确地更新你的 UI,它就不会自动更新。它不会因为你的程序(主线程)只是产生一个进程然后休眠然后杀死它(你甚至不需要try/catch block - 你的应用程序的任何线程上的任何异常都会终止它)。在线程中休眠会阻塞它。由于您在主线程 (UI) 中休眠,因此您会阻止应用程序从消息队列中窥视。

【讨论】:

    猜你喜欢
    • 2012-09-06
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-12
    • 1970-01-01
    • 2021-11-10
    相关资源
    最近更新 更多