How do I abort/cancel TPL Tasks?
Solution 1
You can't. Tasks use background threads from the thread pool. Also canceling threads using the Abort method is not recommended. You may take a look at the following blog post which explains a proper way of canceling tasks using cancellation tokens. Here's an example:
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();
}
}
Solution 2
Like this post suggests, this can be done in the following way:
int Foo(CancellationToken token)
{
Thread t = Thread.CurrentThread;
using (token.Register(t.Abort))
{
// compute-bound work here
}
}
Although it works, it's not recommended to use such approach. If you can control the code that executes in task, you'd better go with proper handling of cancellation.
Solution 3
Aborting a Task is easily possible if you capture the thread in which the task is running in. Here is an example code to demonstrate this:
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();
}
I used Task.Run() to show the most common use-case for this - using the comfort of Tasks with old single-threaded code, which does not use the CancellationTokenSource class to determine if it should be canceled or not.
Solution 4
This sort of thing is one of the logistical reasons why Abort
is deprecated. First and foremost, do not use Thread.Abort()
to cancel or stop a thread if at all possible. Abort()
should only be used to forcefully kill a thread that is not responding to more peaceful requests to stop in a timely fashion.
That being said, you need to provide a shared cancellation indicator that one thread sets and waits while the other thread periodically checks and gracefully exits. .NET 4 includes a structure designed specifically for this purpose, the CancellationToken
.
Solution 5
I use a mixed approach to cancel a task.
- Firstly, I'm trying to Cancel it politely with using the Cancellation.
- If it's still running (e.g. due to a developer's mistake), then misbehave and kill it using an old-school Abort method.
Checkout an example below:
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();
}
}
}
Related videos on Youtube
Patrice Pezillier
Updated on August 30, 2021Comments
-
Patrice Pezillier over 2 years
In a thread, I create some
System.Threading.Task
and start each task.When I do a
.Abort()
to kill the thread, the tasks are not aborted.How can I transmit the
.Abort()
to my tasks ?-
Edward Brey about 4 yearsDoes this answer your question? Is it possible to abort a Task like aborting a Thread (Thread.Abort method)?
-
StayOnTarget almost 3 years@EdwardBrey superficially that question asks the same thing, but none of the answers (IMO) are actually relevant. They all seem to talk about Threads, not Tasks.
-
-
Prerak K over 10 yearsNice explanation. I have a question, how does it work when we don't have an anonymous method in the Task.Factory.StartNew ? like Task.Factory.StartNew(() => ProcessMyMethod(),cancellationToken)
-
Christoph Fink almost 10 yearsThanks for this idea. Used this approach to implement a timeout for some external code, which has no
CancellationToken
support... -
mehmet6parmak almost 10 yearswhat if there is a blocking call which does not return inside the executing task?
-
Joel almost 10 years+1 for giving a different approach while stating its fallbacks. I didn't know this could be done :)
-
Martin Meeser over 9 yearsAFAIK thread.abort will leave you unknown about your stack, it might be invalid. I have never tried it but I guess starting a thread in seperate app domain that thread.abort will be save! Besides, a whole thread is wasted in your solution just to abort one task. You would not have to use tasks but threads in first place. (downvote)
-
Florian Rappl over 9 yearsAs I wrote - this solution is a last resort that might be considered under certain circumstances. Of course a
CancellationToken
or even simpler solutions that are race-condition free should be considered. The code above does only illustrate the method, not the area of usage. -
Mark over 9 years@mehmet6parmak I think the only thing you can do then is use
Task.Wait(TimeSpan / int)
to give it a (time-based) deadline from the outside. -
Cheshire Cat over 9 yearsWhat if I have my custom class to manage the execution of methods inside a new
Task
? Something like:public int StartNewTask(Action method)
. Inside theStartNewTask
method I create a newTask
by:Task task = new Task(() => method()); task.Start();
. So how can I manage theCancellationToken
? I would also like to know if likeThread
I need to implement a logic to check if there're some Tasks that are still hanging and so kill them whenForm.Closing
. WithThreads
I useThread.Abort()
. -
Hi-Angel over 9 yearsOmg, what a bad example! It is a simple boolean condition, of course it is the first what one would try! But i.e. I have a function in a separate Task, which may take much time to be ended, and ideally it shouldn't know anything about a threading or whatever. So how do I cancel the function with your advice?
-
Ivaylo Slavov over 8 yearsI think this approach might have unknown consequences and I would not recommend it in production code. Tasks are not always guaranteed to be executed in a different thread, meaning they can be ran in the same thread as the one that created them if the scheduler decides so (which will mean the main thread will be passed to the
thread
local variable). In your code you might then end up aborting the main thread, which is not what you really want. Perhaps a check if the threads are the same before the abort would be a good think to have, if you insist on aborting -
Sam over 7 yearsThanks for solution! We can just pass token to method and cancel tokensource, instead of somehow getting thread instance from method and aborting this instance directly.
-
Gordon Bean over 7 years@Martin - As I have researched this question on SO, I see you have down-voted several answers that use Thread.Abort to kill tasks, but you have not provided any alternative solutions. How can you kill 3rd party code that does not support cancellation and is running in a Task?
-
tekHedd over 7 yearsThe only solution I can find is to use my own thread pool, and if it does become necessary to abort a stuck thread, replace it manually. It's just not practical to use Tasks where you might have to use Abort, which means that third party code and async also don't mix, as far as I'm concerned.
-
user2288650 over 6 yearsDoes this method work for blocking functions. I am trying to reset a blocking function but this does not seem to help. The blocking function linger after calling- CancellationTokenSource.cancel();
-
John Henckel almost 5 years@GordonBean Here is a post that gives a nice general purpose way to abort threads safely. stackoverflow.com/a/55709530/1812732
-
Theodor Zoulias about 4 yearsThis code fails with a runtime exception: System.InvalidOperationException: RunSynchronously may not be called on a task that was already started.
-
Edward Brey about 4 years@TheodorZoulias Good catch. Thanks. I fixed the code and generally improved the answer.
-
Theodor Zoulias about 4 yearsYeap, this fixed the bug. Another caveat that it should be probably mentioned is that
Thread.Abort
is not supported on .NET Core. Attempting to use it there results to an exception: System.PlatformNotSupportedException: Thread abort is not supported on this platform. A third caveat is that theSingleThreadTaskScheduler
can not be used effectively with promise-style tasks, in other words with tasks created withasync
delegates. For example an embeddedawait Task.Delay(1000)
runs in no thread, so it is unaffected be thread events. -
Edward Brey about 4 years"You can't. Tasks use background threads from the thread pool." That's not necessarily true. You can create a dedicated thread for your task and then abort that thread.
-
Edward Brey about 4 yearsThe task's thread that gets aborted may be a thread-pool thread or the thread of the caller invoking the task. To avoid this, you can use a TaskScheduler to specify a dedicated thread for the task.
-
Toolkit over 3 years@Mark you are wrong, Task.Wait will just abandon the task
-
Toolkit over 3 years'SingleThreadTaskScheduler' does not implement inherited abstract member 'TaskScheduler.TryExecuteTaskInline(Task, bool)
-
Edward Brey over 3 years@Toolkit Good catch. The last method had the wrong name. It was supposed to be
TryExecuteTaskInline
. I updated the code snippet. -
Toolkit over 3 years@EdwardBrey thank you, still
Abort()
doesn't really abort anything, it works as CancellationToken, can't break long operation -
Edward Brey over 3 years@Toolkit
Abort()
here is Thread.Abort, which "Raises a ThreadAbortException in the thread on which it is invoked". It does so immediately, even amid a long operation. That's why you see all the caveats in the remarks. It is unrelated toCancellationToken
. -
Latency almost 3 yearsThis is no longer supported in .NET 5.0+ You will want to look at alternatives to this.
-
Latency almost 3 yearsThis is no longer supported in .NET Framework versions as of 5.0+