我试图为我的视图模型创建一个帮助器方法,该方法需要执行一系列操作,并且会阻止同时发生的其他操作集合。
我相信这是使用Task.ContinueWith
的主要候选人,而我原来的硬编码功能在使用此方法时没有问题,但是当我尝试在运行时构建操作时,我遇到的问题是任务的运行顺序与我预期的不同。
我的班级看起来像:
internal abstract class ViewModel : IViewModel
{
private readonly AutoResetEvent autoResetEvent = new AutoResetEvent(true);
protected Task SynchronousTask(IList<Action> actions)
{
var initialTask = new Task(() => this.autoResetEvent.WaitOne());
for (var i = 0; i < actions.Count; i++)
{
var i1 = i;
initialTask.ContinueWith(task => actions[i1]());
}
initialTask.ContinueWith(task => this.autoResetEvent.Set());
initialTask.Start();
return initialTask;
}
}
基本上我想等AutoResetEvent
阻止运行任何新任务,直到设置完毕。然后我遍历每个任务,将它们添加为初始任务的延续,最后以延续结束来设置AutoResetEvent
。
从理论上讲,这看起来应该可行,但是当我运行它时,我最终会以不正确的顺序运行延续。
我知道在不使用ContinueWith
的情况下还有其他方法可以做到这一点,但我想知道使用此方法我出错的地点和方式。
答案 0 :(得分:5)
当你向同一个任务添加多个延续时,就像在你的例子中一样 - 它们按照一定的顺序启动(据我所知,该订单没有记录,你不应该依赖它 - 但似乎它们是按照先出顺序开始的,但是它们不按特定顺序运行。它们启动后 - 它们都并行运行。因此,在您的情况下,所有操作autoResetEvent.Set()
几乎会在initialTask
完成后同时执行。如果您需要顺序执行 - 只需将所有代码放在一个Task
中并运行它,就不需要在这里使用ContinueWith
。如果您确实想要使用ContinueWith
- 连续延期(对之前ContinueWith
的结果调用ContinueWith
)。
答案 1 :(得分:2)
您只需要链接到最后一个任务,而不是初始任务。 想象一下,将下一个任务挂钩到上一个任务,而不是将所有任务挂钩到第一个任务。
public static Task SynchronousTask(List<Action> actions)
{
var initialTask = new Task(() => autoResetEvent.WaitOne());
Task lastTask = initialTask;
for (int i = 0; i < actions.Count; i++)
{
int i1 = i;
lastTask = lastTask.ContinueWith(task => actions[i1]()); // here
}
lastTask.ContinueWith(task => autoResetEvent.Set());
initialTask.Start();
return initialTask;
}