分配Task.ContinueWith的正确形式是什么

时间:2014-02-12 23:51:35

标签: c# .net multithreading

我正在查看页面http://msdn.microsoft.com/en-us/library/dd997415(v=vs.110).aspx

中的最后一个示例
var task1 = Task.Factory
       .StartNew(() => {...})
       .ContinueWith((t) => {...})

将任务放置到线程池以及为刚刚创建的任务注册的一些后处理处理程序的示例的想法。但是这个代码看起来很危险,即使在操作的.Net原子性方面也是如此。

相反,我建议:

var task1 = new Task(()=>{...})
task1.ContinueWith((t) => {...})
task1.Start();

所以我怀疑第一种形式在分配后处理程序处理器之前存在任务完成的机会。 如果我错了,请提供一些反馈和解释。

2 个答案:

答案 0 :(得分:2)

流利的语法更容易阅读imo,虽然这只是风格问题。

更重要的是,继续任务在前提完成之前被阻止开始,而不是由前提完成特别触发。这意味着如果前一个任务恰好在ContinueWith()返回之前完成,则继续任务将立即启动(因为它不会被阻止启动),而不是被触发。

虽然这是一篇关于延续的有用文章:http://msdn.microsoft.com/en-us/library/ee372288%28v=vs.110%29.aspx

,但这篇文章的记录并不十分清楚

另见第一个答案: http://social.msdn.microsoft.com/Forums/vstudio/en-US/03f14ead-8b68-47bd-83fa-be9d2f6014b2/how-to-use-continuewith?forum=parallelextensions

“如果在已经完成的任务上调用了ContinueWith,继续仍将正确运行,立即安排执行。当你亲密时,如果我们不这样做,那么将会出现严重的竞争条件使用ContinueWith非常容易出错“

答案 1 :(得分:1)

第一个代码片段中没有竞争条件,除非您从任务的lambda中访问task1。即使任务在ContinueWith附加到任务之前完成,也会调用ContinueWith lambda。

您无需访问task1 lambda中的ContinueWith,就此提供了antecedentTask参数:

var task1 = Task.Factory.StartNew(() => {/* ... */}).ContinueWith(
    (antecedentTask) => { /* use antecedentTask here, not task1 */ }); 

Task.Factory.StartNew是推荐new Task()以上任务的方式,建议Task.Run优先于Task.Factory.StartNew。查看Stephen Toub撰写的这些博文:

"Task.Factory.StartNew" vs "new Task(...).Start"

"Task.Run vs Task.Factory.StartNew"

根据我的经验,如果您需要从任务自己的操作(例如this)访问new Task()对象,您可能只需要通过Task构造函数构建任务。非常罕见。