如何将ThreadPool.QueueUserWorkItem中的信息传递回UI线程?

Ian*_*n P 4 c# wpf multithreading .net-3.5

我有一个相当简单的线程问题.

我正在编写一个简单的实用程序,它将根据用户定义的参数运行各种SQL脚本.

为了保持UI响应并提供有关正在执行的脚本状态的反馈,我决定使用ThreadPool.QueueUserWorkItem适合处理各种脚本的执行(通过SMO).

但是,我对如何中继SMO将返回UI线程的输出信息感到困惑.

对于这个实用程序,我使用WPF和MVVM进行演示.我想我会有一个ScriptWorker类,我可以传递参数和位置以及运行脚本的顺序.

在我运行每个脚本之后,我想以某种方式将结果返回到UI线程,以便它更新输出窗口,然后我希望工作者转移到下一个任务.

我确定这是一个基本问题,但在看到QueueUserWorkItem并看到我基本上通过回调开始工作后,我不确定我将如何完成我想要完成的任务.

我基于这篇微软文章做了我的假设:

http://msdn.microsoft.com/en-us/library/3dasc8as(VS.80).aspx

谢谢(你的)信息!

Ste*_*ary 8

QueueUserWorkItem技术上会起作用,但是非常低级.有更简单的方法.

我建议使用Task.NET 4.0 的新功能.它完全符合您的要求,包括将结果或错误条件同步到另一个线程(在本例中为UI线程).

如果.NET 4.0不是一个选项,那么我建议BackgroundWorker(如果您的后台处理不是太复杂),或者像汉斯提到的异步委托.如果使用异步委托,则使用AsyncOperation该类将结果封送回UI线程.

Task选项非常好,因为它非常自然地处理父/子任务.BackgroundWorker不能嵌套.另一个考虑是取消; Task并且BackgroundWorker内置支持取消,但对于异步代表,您必须自己做.

唯一TaskBackgroundWorker进度报告更复杂的地方.它不是那么容易BackgroundWorker,但我在我的博客上有一个包装器,以尽量减少这一点.

总结一下,按优先顺序排列:

  1. Task - 支持正确的错误编组,结果的概念,取消和父/子嵌套.它的一个弱点是进度报告并不简单(您必须创建另一个任务并将其安排到UI线程).
  2. BackgroundWorker - 支持正确的错误编组,结果的概念,取消和进度报告.它的一个缺点是它不支持父/子嵌套,这限制了它在API中的使用,例如,对于业务层.
  3. Delegate.BeginInvokewith AsyncOperation- 支持正确编组错误,结果的概念和进度报告.但是,没有内置的取消概念(尽管可以使用a手动完成volatile bool).它也不支持父/子嵌套.
  4. Delegate.BeginInvokewith SynchronizationContext- 除了SynchronizationContext直接使用之外,它与选项(3)相同.代码稍微复杂一些,但权衡是支持父/子嵌套.所有其他限制与选项(3)相同.
  5. ThreadPool.QueueUserWorkItemwith AsyncOperationSynchronizationContext- 支持进度报告的概念.取消遇到与选项(3)相同的问题.错误的编组并不容易(特别是保留堆栈跟踪).此外,只有SynchronizationContext使用父/子嵌套而不是AsyncOperation.此外,此选项不支持结果的概念,因此任何返回值都需要作为参数传递.

如你所见,Task是明显的赢家.除非.NET 4.0不是一个选项,否则应该使用它.