如何中止/取消TPL任务?

在一个线程中,我创build了一些System.Threading.Task并开始每个任务。

当我做.Abort()来杀死线程时,任务不会中止。

如何将.Abort()传输到我的任务?

你不能。 任务使用线程池中的后台线程。 不build议使用Abort方法取消线程。 您可以查看以下博客文章 ,其中解释了使用取消令牌取消任务的正确方法。 这是一个例子:

 class Program { static void Main() { var ts = new CancellationTokenSource(); CancellationToken ct = ts.Token; Task.Factory.StartNew(() => { while (true) { // do some heavy work here Thread.Sleep(100); if (ct.IsCancellationRequested) { // another thread decided to cancel Console.WriteLine("task canceled"); break; } } }, ct); // Simulate waiting 3s for the task to complete Thread.Sleep(3000); // Can't wait anymore => cancel this task ts.Cancel(); Console.ReadLine(); } } 

如果捕获正在运行任务的线程,则放弃任务很容易。下面是一个示例代码来演示此操作:

 void Main() { Thread thread = null; Task t = Task.Run(() => { //Capture the thread thread = Thread.CurrentThread; //Simulate work (usually from 3rd party code) Thread.Sleep(1000); //If you comment out thread.Abort(), then this will be displayed Console.WriteLine("Task finished!"); }); //This is needed in the example to avoid thread being still NULL Thread.Sleep(10); //Cancel the task by aborting the thread thread.Abort(); } 

我使用Task.Run()来显示最常见的用例 – 使用旧的单线程代码的舒适任务,它不使用CancellationTokenSource类来确定它是否应该被取消。

像这个post所build议的,这可以通过以下方式完成:

 int Foo(CancellationToken token) { Thread t = Thread.CurrentThread; using (token.Register(t.Abort)) { // compute-bound work here } } 

虽然有效,但不build议使用这种方法。 如果你能控制在任务中执行的代码,你最好去正确的处理取消。

这种事情是Abort被弃用的后勤​​原因之一。 首先, 不要使用Thread.Abort()来取消或停止一个线程,如果可能的话。 Abort()只能用来强制杀死一个没有及时响应更多和平请求的线程。

这就是说,你需要提供一个共享的取消指标,一个线程设置并等待另一个线程定期检查并正常退出。 .NET 4包含专门为此devise的结构CancellationToken

你不应该直接尝试这样做。 devise你的任务来使用CancellationToken ,并以这种方式取消它们。

另外,我build议通过CancellationToken将主线程更改为函数。 调用Thread.Abort()是一个坏主意 – 它可能导致各种难以诊断的问题。 相反,该线程可以使用与您的任务使用相同的“ CancellationTokenSource并且可以使用相同的CancellationTokenSource触发取消所有任务和主线程。

这将导致更简单,更安全的devise。

要回答Prera​​k K在不使用Task.Factory.StartNew()中的匿名方法时如何使用CancellationToken的问题,请将CancellationToken作为parameter passing给您以StartNew()开始的方法,如MSDN示例中所示这里 。

例如

 var tokenSource = new CancellationTokenSource(); var token = tokenSource.Token; Task.Factory.StartNew( () => DoSomeWork(1, token), token); static void DoSomeWork(int taskNum, CancellationToken ct) { // Do work here, checking and acting on ct.IsCancellationRequested where applicable, } 

您可以使用CancellationToken来控制任务是否被取消。 你是说在开始之前放弃它(“我不知道,我已经做了这个”),还是实际上在中间打断它? 如果前者, CancellationToken可以帮助; 如果是后者,则可能需要实现自己的“保释”机制,并在任务执行的适当位置检查是否应该快速失败(您仍然可以使用CancellationToken来帮助您,但手册更简单一些)。

MSDN有关于取消任务的文章: http : //msdn.microsoft.com/en-us/library/dd997396.aspx

我使用混合的方法取消任务。

  • 首先,我试图取消它礼貌地使用取消 。
  • 如果它仍然在运行(例如由于开发者的错误),那么使用老派的Abort方法会造成不正确的行为。

结帐一个例子如下:

 private CancellationTokenSource taskToken; private AutoResetEvent awaitReplyOnRequestEvent = new AutoResetEvent(false); void Main() { // Start a task which is doing nothing but sleeps 1s LaunchTaskAsync(); Thread.Sleep(100); // Stop the task StopTask(); } /// <summary> /// Launch task in a new thread /// </summary> void LaunchTaskAsync() { taskToken = new CancellationTokenSource(); Task.Factory.StartNew(() => { try { //Capture the thread runningTaskThread = Thread.CurrentThread; // Run the task if (taskToken.IsCancellationRequested || !awaitReplyOnRequestEvent.WaitOne(10000)) return; Console.WriteLine("Task finished!"); } catch (Exception exc) { // Handle exception } }, taskToken.Token); } /// <summary> /// Stop running task /// </summary> void StopTask() { // Attempt to cancel the task politely if (taskToken != null) { if (taskToken.IsCancellationRequested) return; else taskToken.Cancel(); } // Notify a waiting thread that an event has occurred if (awaitReplyOnRequestEvent != null) awaitReplyOnRequestEvent.Set(); // If 1 sec later the task is still running, kill it cruelly if (runningTaskThread != null) { try { runningTaskThread.Join(TimeSpan.FromSeconds(1)); } catch (Exception ex) { runningTaskThread.Abort(); } } } 

任务通过取消令牌获得一级支持取消 。 使用取消令牌创build您的任务,并明确地通过这些取消任务。

任务正在ThreadPool上执行(至less,如果你使用的是默认工厂),所以中止线程不会影响任务。 有关中止任务,请参阅msdn上的任务取消 。