How do I abort/cancel TPL Tasks?

C#.NetMultithreadingTaskAbort

C# Problem Overview


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 ?

C# Solutions


Solution 1 - C#

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 - C#

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 3 - C#

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 4 - C#

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 - C#

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();
		}
	}
}

Solution 6 - C#

To answer Prerak K's question about how to use CancellationTokens when not using an anonymous method in Task.Factory.StartNew(), you pass the CancellationToken as a parameter into the method you're starting with StartNew(), as shown in the MSDN example here.

e.g.

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, 

}

Solution 7 - C#

You should not try to do this directly. Design your tasks to work with a CancellationToken, and cancel them this way.

In addition, I would recommend changing your main thread to function via a CancellationToken as well. Calling Thread.Abort() is a bad idea - it can lead to various problems that are very difficult to diagnose. Instead, that thread can use the same Cancellation that your tasks use - and the same CancellationTokenSource can be used to trigger the cancellation of all of your tasks and your main thread.

This will lead to a far simpler, and safer, design.

Solution 8 - C#

Tasks have first class support for cancellation via cancellation tokens. Create your tasks with cancellation tokens, and cancel the tasks via these explicitly.

Solution 9 - C#

You can use a CancellationToken to control whether the task gets cancelled. Are you talking about aborting it before it's started ("nevermind, I already did this"), or actually interrupting it in middle? If the former, the CancellationToken can be helpful; if the latter, you will probably need to implement your own "bail out" mechanism and check at appropriate points in the task execution whether you should fail fast (you can still use the CancellationToken to help you, but it's a little more manual).

MSDN has an article about cancelling Tasks: http://msdn.microsoft.com/en-us/library/dd997396.aspx

Solution 10 - C#

Task are being executed on the ThreadPool (at least, if you are using the default factory), so aborting the thread cannot affect the tasks. For aborting tasks, see Task Cancellation on msdn.

Solution 11 - C#

I tried CancellationTokenSource but i can't do this. And i did do this with my own way. And it works.

namespace Blokick.Provider
{
    public class SignalRConnectProvider
    {
        public SignalRConnectProvider()
        {
        }

        public bool IsStopRequested { get; set; } = false; //1-)This is important and default `false`.

        public async Task<string> ConnectTab()
        {
            string messageText = "";
            for (int count = 1; count < 20; count++)
            {
                if (count == 1)
                {
                //Do stuff.
                }

                try
                {
                //Do stuff.
                }
                catch (Exception ex)
                {
                //Do stuff.
                }
                if (IsStopRequested) //3-)This is important. The control of the task stopping request. Must be true and in inside.
                {
                    return messageText = "Task stopped."; //4-) And so return and exit the code and task.
                }
                if (Connected)
                {
                //Do stuff.
                }
                if (count == 19)
                {
                //Do stuff.
                }
            }
            return messageText;
        }
    }
}

And another class of the calling the method:

namespace Blokick.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class MessagePerson : ContentPage
    {
        SignalRConnectProvider signalR = new SignalRConnectProvider();

        public MessagePerson()
        {
            InitializeComponent();

            signalR.IsStopRequested = true; // 2-) And this. Make true if running the task and go inside if statement of the IsStopRequested property.

            if (signalR.ChatHubProxy != null)
            {
                 signalR.Disconnect();
            }

            LoadSignalRMessage();
        }
    }
}

Solution 12 - C#

You can abort a task like a thread if you can cause the task to be created on its own thread and call Abort on its Thread object. By default, a task runs on a thread pool thread or the calling thread - neither of which you typically want to abort.

To ensure the task gets its own thread, create a custom scheduler derived from TaskScheduler. In your implementation of QueueTask, create a new thread and use it to execute the task. Later, you can abort the thread, which will cause the task to complete in a faulted state with a ThreadAbortException.

Use this task scheduler:

class SingleThreadTaskScheduler : TaskScheduler
{
	public Thread TaskThread { get; private set; }

	protected override void QueueTask(Task task)
	{
		TaskThread = new Thread(() => TryExecuteTask(task));
		TaskThread.Start();
	}

	protected override IEnumerable<Task> GetScheduledTasks() => throw new NotSupportedException(); // Unused
	protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) => throw new NotSupportedException(); // Unused
}

Start your task like this:

var scheduler = new SingleThreadTaskScheduler();
var task = Task.Factory.StartNew(action, cancellationToken, TaskCreationOptions.LongRunning, scheduler);

Later, you can abort with:

scheduler.TaskThread.Abort();

Note that the caveat about aborting a thread still applies: > The Thread.Abort method should be used with caution. Particularly when you call it to abort a thread other than the current thread, you do not know what code has executed or failed to execute when the ThreadAbortException is thrown, nor can you be certain of the state of your application or any application and user state that it is responsible for preserving. For example, calling Thread.Abort may prevent static constructors from executing or prevent the release of unmanaged resources.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPatrice PezillierView Question on Stackoverflow
Solution 1 - C#Darin DimitrovView Answer on Stackoverflow
Solution 2 - C#Florian RapplView Answer on Stackoverflow
Solution 3 - C#starteleportView Answer on Stackoverflow
Solution 4 - C#Adam RobinsonView Answer on Stackoverflow
Solution 5 - C#Alex KlausView Answer on Stackoverflow
Solution 6 - C#JoolsView Answer on Stackoverflow
Solution 7 - C#Reed CopseyView Answer on Stackoverflow
Solution 8 - C#Tim LloydView Answer on Stackoverflow
Solution 9 - C#HankView Answer on Stackoverflow
Solution 10 - C#Oliver HanappiView Answer on Stackoverflow
Solution 11 - C#Hasan Tuna OruçView Answer on Stackoverflow
Solution 12 - C#Edward BreyView Answer on Stackoverflow