【问题标题】:Howto wait work thread in the main Form?如何在主窗体中等待工作线程?
【发布时间】:2011-04-21 15:25:31
【问题描述】:

阅读了几篇文章后,我仍然不确定我是否理解多线程来解决我的问题 特殊问题。

我有一个主窗体,它将启动一个后台工作线程(worker)。工作线程将执行 While(!Stopping) 无限循环,并在每次迭代结束时休眠,由全局停止对象(只读锁定对象)终止。当用户按下停止按钮时工作正常, worker 将在当前迭代后停止。

现在我想当用户关闭主窗体时,它会先设置停止标志,让工作线程 完成目前的工作。之后主窗体将关闭。看起来很简单,但我无法让它工作。

我尝试了worker.Join(),或者在while循环中测试woker.IsAlive,但是由于某种原因,这两种情况都会在几秒钟后锁定应用程序(主窗体)?

以下是我在 Form_Closing 事件处理程序中的代码(不工作):

               // Tell the thread to stop the file
                Stop();
                Logger.Info("Stopping the thread by Close the application");
               //Not working as well                    
               //worker.Join();
                while (worker.IsAlive)
                {
                    Thread.Sleep(5000);
                    Logger.Info("After sleep for 5 seconds");
                }
                Logger.Info("worker thread stopped");

有趣的是,工作线程似乎总是在每次循环迭代结束之前写入日志事件,然后日志条目的其余部分将是里面的主窗体事件 while(worker.IsAlive) 循环。

【问题讨论】:

    标签: c# multithreading


    【解决方案1】:

    Join 会一直等待线程,在 UI 线程中使用它会使应用程序看起来被锁定。 IsAlive 不会阻止 GUI 线程中的任何内容,它是您的 Thread.Sleep。

    改为这样做:

    while (worker.IsAlive)
    {
        Thread.sleep(50);
        Application.DoEvents();
    }
    

    【讨论】:

      【解决方案2】:

      您正在创建一个死锁,以某种方式在您请求并释放锁定对象的任何地方放置一个断点。您也可以使用system.threading.monitor 类来测试锁是否可用,而不是创建死锁。非常熟悉 VS 中的线程窗口。

      【讨论】:

      • 不幸的是,这是我们第一个需要 .NET 4.0 的项目,因此我目前正在使用 VS2010 Express。看起来它没有用于调试的线程窗口。
      【解决方案3】:

      请记住,您使用的任何导致 UI 线程暂停其正常的泵送消息义务的代码都将对用户表现为挂起。也就是说,不要调用任何可能阻塞的方法,包括Thread.JoinThread.SleepWaitHandle.WaitOne等。

      由于您希望工作人员在关闭表单时终止,所以我建议在停止信号发送到工作线程后让表单关闭。在调用Application.Run 之后,将Thread.Join 调用添加到应用程序的入口点。由于您正在关闭应用程序,因此如果线程没有及时响应,则可以安全地调用Thread.Abort。这是一些示例代码。

      public void Main(string[] args)
      {
        var form = new YourForm();
        Application.Run(form);
        if (!form.WorkerThread.Join(TIME_TO_WAIT))
        {
          form.WorkerThread.Abort();
        }
      }
      

      【讨论】:

      • 感谢 Brian Gideon,我确实测试了您的解决方案,但我的主窗体将立即关闭。问题是我并不真正理解您的解决方案,不确定我是否以正确的方式实施它。
      • 基本上我现在只需调用 Stop() 在表单的关闭事件中为工作线程设置停止标志。而且我认为那时我的主窗体将被关闭,并且执行将返回 program.cs 到该行: if(!form.WorkerThread.Join(TIME_TO_WAIT)) 但由于主窗体此时已关闭,并且似乎 Logger 功能从那时起也不起作用,我怎么知道从那时起发生了什么?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-07
      • 1970-01-01
      • 2018-07-16
      相关资源
      最近更新 更多