取消任务并等待它完成
问题描述:
我有一个耗时的任务,我需要在单独的线程中运行以避免锁定GUI线程。随着此任务的进展,它会更新特定的GUI控件。取消任务并等待它完成
美中不足的是,面前的任务是在用户可能移动到图形用户界面的另一部分,并且在这种情况下,我必须:
- 取消正在进行的任务(如果它是活动)
- 等到它完成取消:这是至关重要的,因为耗时的任务的目标是更新特定的控件。如果不止一个线程试图立即执行,事情可能会变得混乱。
- 启动从头
任务对于一个具体的例子,设想的形式主要有两个部分:一是在您浏览目录树,和另一个在那里你显示缩略图。当用户导航到另一个目录时,需要刷新缩略图。
首先我想到使用BackgroundWorker
和AutoResetEvent
来等待取消,但是我一定弄错了一些东西,因为取消时我被锁定了。然后我读了关于TPL,它应该取代BGW和更原始的机制。
这可以使用TPL轻松完成吗?
答
有几件事情需要注意:
可以从
CancellationTokenSource
任务取消获得
CancellationToken
是合作行动:如果你的任务没有定期检查CancellationToken.IsCancellationRequested
财产,无论你尝试取消任务多少次都没有关系,它会快乐地流失。
那些东西说,这里的总体思路:
void Main()
{
var tokenSource = new CancellationTokenSource();
var myTask = Task.Factory
.StartNew(() => DoWork(tokenSource.Token), tokenSource.Token);
Thread.Sleep(1000);
// ok, let's cancel it (well, let's "request it be cancelled")
tokenSource.Cancel();
// wait for the task to "finish"
myTask.Wait();
}
public void DoWork(CancellationToken token)
{
while(!token.IsCancellationRequested)
{
// Do useful stuff here
Console.WriteLine("Working!");
Thread.Sleep(100);
}
}
是否还好只是一次创建令牌源及其令牌传递到'StartNew'每一次? – 2013-02-15 12:49:09
把它想象成一个小孩的两个罐子放在一个串上(好吧,一个给N罐头:你有一端,所有开始的任务都可以,你一边喊“取消”,所有分享令牌的人都会听到它。 – JerKimball 2013-02-15 15:27:17
@dario_ramos我相信你的评论中的问题是在评论[这里](http://*.com/questions/14896248/deadlock-when-waiting-for-task-to-finish)中回答的,但为了完整性'因此,答案是否定的 - 'CancellationTokenSource'不能被重置和取消;如果你要求取消一个,那么如果你想再次取消,你必须用一个新的取代它 – shambulator 2013-02-16 12:05:36