2010-10-06 77 views
0

在阅读了几篇文章后,我仍然不确定我是否理解了多线程来解决我的特定问题。如何在主窗体中等待工作线程?

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

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

我试过了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)循环内部成为主窗体事件。

回答

2

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

做somethnig这样,而不是:

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

谢谢,这个解决方案似乎运作良好。 – 2010-10-06 21:40:50

0

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

+0

不幸的是,这是我们第一个需要.NET 4.0的项目,因此我目前正在使用VS2010 Express。看起来不像它有调试线程窗口。 – 2010-10-06 21:47:49

0

请记住,您使用导致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(); 
    } 
} 
+0

感谢Brian Gideon,我测试了您的解决方案,但我的主表单将立即关闭。问题在于我并没有真正理解你的解决方案,我不确定我是否以正确的方式实施了它。 – 2010-10-06 22:01:52

+0

基本上我现在只需调用Stop()在窗体的关闭事件中为工作线程设置停止标志。我认为在这一点上我的主窗体将被关闭,执行将返回到program.cs的行:if(!form.WorkerThread。加入(TIME_TO_WAIT)),但是因为主窗体在那一点关闭了,并且似乎Logger函数也没有从那一点开始工作,所以我怎么知道从那一点发生了什么? – 2010-10-06 22:11:07