2009-08-14 95 views
0

对,我的应用程序偶尔会启动一些执行某些操作的后台线程。主线程正在等待更新接口的后台线程

由于它做它的东西,它也更新主窗口上的进度条。它通过调用Invoke来获取主线程来更新接口。

当用户关闭应用程序时,我希望等到所有后台线程完成后再关闭表单。在表格闭幕事件我有类似的东西

  while (this._Queue.Count > 0) 
      Application.DoEvents(); 

但这不起作用!

后台线程陷入Invoke调用。主线程继续循环调用其DoEvents,我认为这将是它拿起并处理其调用所需的全部内容。但它没有这样做...

为什么不!

+1

嗨, 你在哪里放置在主窗体关闭事件的代码? 最好的问候, Iordan – IordanTanev 2009-08-14 10:05:13

+0

是的,它是在主窗体form_closing事件。 – 2009-08-14 14:11:55

回答

0

对,我从不同的角度对问题进行了整理。没有更多的等待线程完成...

我刚刚在工作线程中添加了一个变量bool KillOnThreadFinish。

然后在主窗体关闭的窗体中检查线程是否正在运行。如果它是我设置KillOnThreadFinish = true,我设置e.cancel = true(以防止窗体关闭在那一点),我设置MainForm.Enabled = false(以防止用户再次关闭窗体)。

然后当线程完成其工作时,它检查KillOnThreadFinish,如果True调用Application.Exit()并且应用程序退出。

似乎工作得很漂亮!

(感谢您尝试家伙。:-))

0

我建议将代码放在窗体的“关闭”事件中。此外,您可以尝试在Application.DoEvents()之后添加Thread.Sleep(100)

另外,我想创建一个在启动时设置ManualResetEvent称为threadDone或类似的线程启动,并通过线程设置为表示它完成工作之前(通过true到事件的构造函数),被重置。

然后,你可以改写你的循环如下:

while (!threadDone.WaitOne(100, true)) 
{ 
    Application.DoEvents(); 
    Thread.Sleep(100); 
} 

这可能会帮助 - 但我还没有真正尝试过现在这种权利。我通常所做的是使用重置事件来检查应用程序或表单是否可以关闭。如果线程没有完成,我会向用户显示一条消息。

1

BackgroundWorker提供了一种便捷的方式来运行后台线程,同时允许使用.NET事件轻松地报告进度。您可以将ProgressBar UI更新连接到ProgressChanged事件处理程序,并通过RunWorkerCompleted将完成报告给您。如果你只有一个后台线程,这比自己的线程处理代码简单得多。这里是MSDN文章:

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

如果你坚持使用常规的线程,那么我会考虑使用加入到等待线程来完成。这样可以不断处理正常的消息,并在紧密的循环中保存轮询。这里还有更多的信息:

http://msdn.microsoft.com/en-us/library/95hbf2ta.aspx

此外,还有一些采取超时参数(无论是一个Int32毫秒或TimeSpan对象)的过载。如果在此时间过后线程还没有完成,则会抛出异常。这有助于捕捉在您尝试关闭时卡住的线程。更多在这里:

http://msdn.microsoft.com/en-us/library/6b1kkss0.aspx

我希望这有助于。

+0

Join似乎不起作用,它仍然陷入死锁,主线程停留在Join上,并且工作线程停留在Invoke上。 – 2009-08-14 14:13:13

0

主线程不应该等待任何其他线程,而是另一个线程应该表示其工作已完成。

在你的情况下,我只是使用另一个线程的Control.InvokeControl.BeginInvoke方法来更新UI。

+0

我是,它不工作.. – 2009-08-14 14:33:33

+0

主线程不应该被阻塞等待的东西,它应该什么也不做。同时,OTHER线程完成它的工作并通知主线程。 – 2009-08-14 17:39:37