How to cancel a task on Thread.Abort() - c#

I'm implementing a Method called by someone else. If my Method takes to long the caller will call Thread.Abort(). I start some tasks in my Method, and need to cancel those if my thread get aborted.
I currently guess the timeout I have and cancel the tasks after this timespan. It is not always the same timeout, depending on the operations executed before my method.
Are there a way to tie my tasks to that thread lifetime?
Update
To prevent any further comments, that I should not use Thread.Abort(), this is the code that handles the abort (not called by me, can't change that):
using (var cancelationTokenSource = new CancellationTokenSource())
{
try
{
DoWork(cancelationTokenSource.Token);
}
catch (ThreadAbortException)
{
cancelationTokenSource.Cancel();
throw;
}
}
I use the CancellationToken not Thread.Abort()

You can handle ThreadAbortException to deal with cleanup, including aborting other threads if ncessary.
void MyThreadProc()
{
try
{
//Do interesting things
}
catch ( ThreadAbortException e )
{
childThread.Abort();
}
}

Related

Method should throw an exception when called by another thread before completion

I have a method StartProcess(). I want this method to throw an exception if the same method is called by another thread at the same time or by the same initial thread before EndProcess() is called.
I tried the Monitor class but I wasn't sure how to apply it to the above stated case. What I saw that was close to what I was looking for was:
var obj = new Object();
// Define the critical section.
Monitor.Enter(obj);
try {
// Code to execute one thread at a time.
}
// catch blocks go here.
finally {
Monitor.Exit(obj);
}
I need guidance to handle my exact stated scenario. I've been trying all day but couldn't get it to work.
You need a synchronization mechanism that disallows reentrancy, and the Monitor is not one of them (it is reentrant by design). My suggestion is to use a SemaphoreSlim, which is not reentrant. This mechanism doesn't look to see which thread is calling it. It's just a simple counter. In order to acquire the semaphore if it's available, or return instantly if it's not available, you can invoke the Wait method with a zero millisecondsTimeout, like this:
SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
bool acquired = semaphore.Wait(0);
if (!acquired) throw new InvalidOperationException();
try
{
// Code to execute disallowing concurrency
}
finally
{
semaphore.Release();
}
It seems you are looking for the ManualResetEventSlim:
ManualResetEventSlim resetEvent = new ManualResetEventSlim();
// Block other calls.
resetEvent.Wait();
// Reset state to block next calls.
resetEvent.Reset();
try
{
// Your code
}
finally
{
// Set state to allow next call to proceed.
resetEvent.Set();
}

How do you run a variable number of concurrent parametrizable infinite loop type of threads in C#?

I am creating my first multithreading C#/.NET based app that will run on a Azure Service Fabric cluster. As the title says, I wish to run a variable number of concurrent parametrizable infinite-loop type of threads, that will utilize the RunAsync method.
Each child thread looks something like this:
public async Task childThreadCall(...argument list...)
{
while (true)
{
try
{
//long running code
//do something useful here
//sleep for an independently parameterizable period, then wake up and repeat
}
catch (Exception e)
{
//Exception Handling
}
}
}
There are a variable number of such child threads that are called in the RunAsync method. I want to do something like this:
protected override async Task RunAsync(CancellationToken cancellationToken)
{
try
{
for (int i = 0; i < input.length; i++)
{
ThreadStart ts[i] = new ThreadStart(childThreadCall(...argument list...));
Thread tc[i] = new Thread(ts);
tc[i].Start();
}
}
catch (Exception e)
{
//Exception Handling
}
}
So basically each of the child threads run independently from the others, and keep doing so forever. Is it possible to do such a thing? Could someone point me in the right direction? Are there any pitfalls to be aware of?
The RunAsync method is called upon start of the service. So yes it can be used to do what you want. I suggest using Tasks, as they play nicely with the cancelation token. Here is a rough draft:
protected override async Task RunAsync(CancellationToken cancellationToken)
{
var tasks = new List<Task>();
try
{
for (int i = 0; i < input.length; i++)
{
tasks.Add(MyTask(cancellationToken, i);
}
await Task.WhenAll(tasks);
}
catch (Exception e)
{
//Exception Handling
}
}
public async Task MyTask(CancellationToken cancellationToken, int a)
{
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
try
{
//long running code, if possible check for cancellation using the token
//do something useful here
await SomeUseFullTask(cancellationToken);
//sleep for an independently parameterizable period, then wake up and repeat
await Task.Delay(TimeSpan.FromHours(1), cancellationToken);
}
catch (Exception e)
{
//Exception Handling
}
}
}
Regarding pitfalls, there is a nice list of things to think of in general when using Tasks.
Do mind that Tasks are best suited for I/O bound work. If you can post what exactly is done in the long running process please do, then I can maybe improve the answer to best suit your use case.
One important thing it to respect the cancellation token passed to the RunAsync method as it indicates the service is about to stop. It gives you the opportunity to gracefully stop your work. From the docs:
Make sure cancellationToken passed to RunAsync(CancellationToken) is honored and once it has been signaled, RunAsync(CancellationToken) exits gracefully as soon as possible. Please note that if RunAsync(CancellationToken) has finished its intended work, it does not need to wait for cancellationToken to be signaled and can return gracefully.
As you can see in my code I pass the CancellationToken to child methods so they can react on a possible cancellation. In your case there will be a cancellation because of the endless loop.

Cancelling multiple tasks by registering callbacks on cancellation tokens

I have the following code piece with the output below.
I was expecting the second task to be cancelled as it also registers a callback on the cancellation token.
But the cancellation only happens on the first task, where the original cancellation was done.
Aren't cancellations supposed to be propagated to all token instances?
The Microsoft article on Cancellation Tokens does not explain this well.
Any pointers on why this is happening?
Code:
class Program
{
static void Main(string[] args)
{
AsyncProgramming();
Console.ReadLine();
}
private static async void AsyncProgramming()
{
try
{
using (var cts = new CancellationTokenSource())
{
var task2 = CreateTask2(cts);
var task1 = CreateTask1(cts);
Thread.Sleep(5000);
await Task.WhenAll(task2, task1);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine("Both tasks over");
}
private static async Task CreateTask1(CancellationTokenSource cts)
{
try
{
cts.Token.Register(() => { cts.Token.ThrowIfCancellationRequested(); });
await Task.Delay(5000);
Console.WriteLine("This is task one");
cts.Cancel();
Console.WriteLine("This should not be printed because the task was cancelled");
}
catch (Exception e)
{
Console.WriteLine("Task 1 exception: " + e.Message);
Console.WriteLine("Task 1 was cancelled");
}
}
private static async Task CreateTask2(CancellationTokenSource cts)
{
try
{
cts.Token.Register(() =>
{
Console.WriteLine("Write something");
Thread.CurrentThread.Abort();
cts.Token.ThrowIfCancellationRequested();
});
await Task.Delay(8000);
Console.WriteLine("This is task two");
}
catch (Exception e)
{
Console.WriteLine("Task 2 was cancelled by Task 1");
Console.WriteLine(e);
}
}
}
Output:
This is task one
Write something
Task 1 exception: Thread was being aborted.
Task 1 was cancelled
This is task two
Thread was being aborted.
Both tasks over
The first thing is that when you call CancellationToken.Register all it normally does is to store the delegate to call later.
The thread/logic flow calling CancellationTokenSource.Cancel runs all previously registered delegates, regardless of where those were registered from. This means any exception thrown in those normally does not relate in any way to the methods that called Register.
Side note 1: I said normally above, because there is a case where the call to Register will run the delegate right away. I think this is why the msdn documentation is extra confusing. Specifically: if the token was already cancelled, then Register will run the delegate right away, instead of storing it to be ran later. Underneath that happens in CancellationTokenSource.InternalRegister.
The second thing to complete the picture is that all CancellationToken.ThrowIfCancellationRequested does is to throw an exception wherever it is being ran from. That would normally be wherever CancellationTokenSource.Cancel was called from. Note that normally all registered delegates are ran, even if some of those throw an exception.
Side note 2: throwing ThreadAbortException changes the intended logic in the Cancel method, because that special exception can't be caught. When faced with that, cancel stops running any further delegates. The same happens to the calling code, even when catching exceptions.
The last thing to note, is that the presence of the CancellationToken does not affect the logic flow of the methods. All lines in the method run, unless there is code explicitely exiting the method, for example, by throwing an exception. This is what happens if you pass the cancellation token to the Task.Delay calls and it gets cancelled from somewhere else before the time passes. It is also what happens if you were to put calls to CancellationToken.ThrowIfCancellationRequested after specific lines in your method.
It is not just the second task that fails to cancel. Both registrations to the token work and both ThrowIfCancellationRequested fire, but they are not handled because they run in a different thread.
This happens in the background (twice):
An exception of type 'System.OperationCanceledException' occurred in mscorlib.dll but was not handled in user code
What you should do is call cts.Token.ThrowIfCancellationRequested(); in your function instead of registering to the event.
See the examples at https://learn.microsoft.com/en-us/dotnet/standard/threading/cancellation-in-managed-threads
Right now you are combining two ways of cancellation: registering to the token cancel event (Token.Register), and throwing if the token is cancelled (Token.ThrowIfCancellationRequested).
Either you subscribe to the cancel event and perform your own cancel/cleanup logic, or you check in your function code if you should cancel your operation.
An example would look like this:
private static async Task CreateTask2(CancellationToken token)
{
try
{
// Pass on the token when calling other functions.
await Task.Delay(8000, token);
// And manually check during long operations.
for (int i = 0; i < 10000; i++)
{
// Do we need to cancel?
token.ThrowIfCancellationRequested();
// Simulating work.
Thread.SpinWait(5000);
}
Console.WriteLine("This is task two");
}
catch (Exception e)
{
Console.WriteLine("Task 2 was cancelled by Task 1");
Console.WriteLine(e);
}
}
Registration of a delegate by Register is just a way to notify when a token goes to the cancelled state, no more. In order to do the cancellation you need to react on this notification in the code and it's mostly needed when execution you want to cancel goes to a stage where cancellation token isn't verified (for example because a method being executed just doesn't accept CancellationToken as paramater) but you still need some control of cancellation state. But in all cases when you deal with executuon of code which has access to CancellationToken you just don't need to subscribe on the cancellation notification.
In your case the first delegate raises exception and this exception is propagated to the Cancel call only that's why the task is cancelled, but this is improper design as you shouldn't deal with CancellationTokenSource in your tasks and shouldn't initiate a cancellation in there, so I'd say that the first cancellation works only by coincidence. For the second task the delegate is invoked but nothing triggers the cancellation inside the task so why should it be cancelled ?

How to restart thread or any other alternate solution

I am working calling app which automatically calls a number. I am using main thread to query call status(busy,dialing,active, calling, deactivated etc). Whenever call is picked recorded audio will be played using other thread 2. When call status is deactivated main thread will stop audio by stopping thread 2. On next call again when call is picked recorded audio will played using thread 2.
Thread autoReminder = new Thread(new ThreadStart(threadAutoCalling));
//// Main thread on call attend calls
autoReminder.Start();
// On call end, i tried
autoReminder.Abort();
private void threadAutoCalling()
{
try
{
// PlayAudio(#"C:\Users\CheatnPc\Desktop\TextToSpeechAudio\psf1.wav");
PlayAudio(#"C:\Users\CheatnPc\Desktop\TextToSpeechAudio\psf3.wav");
PlayAudio(#"C:\Users\CheatnPc\Desktop\TextToSpeechAudio\sales.wav");
}
catch (Exception ex)
{
throw ex;
}
}
public void PlayAudio(string path)
{
(new Microsoft.VisualBasic.Devices.Audio()).Play(path, Microsoft.VisualBasic.AudioPlayMode.WaitToComplete);
}
after thread abort it can not be started again. How can i do this or is there any alternate solution for this.
Thread's cannot be restarted - when they're done, they're done.
The usual solution would be to simply start a new thread, but when you're doing as little as you are, using a threadpool thread might be a better idea:
Task.Run(threadAutoCalling);
Or even better, if there's an asynchronous way of invoking those PlaySound and Speak, use that - usually, you wouldn't need real CPU work to handle operations like that.
As I understood correctly you want to abort your play of music. For this reason it is more applicable Task class. You can cancel your Task by calling Cancel() method of class CancellationTokenSource.
Example of console application:
CancellationTokenSource cancellationTokenSource =
new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;
Task task = Task.Run(() =>
{
while (!token.IsCancellationRequested)
{
ThreadAutoCalling();
}
token.ThrowIfCancellationRequested();
}, token);
try
{
Console.WriteLine("Press any key to abort the task");
Console.ReadLine();
cancellationTokenSource.Cancel();
task.Wait();
}
catch (AggregateException e)
{
Console.WriteLine(e.InnerExceptions[0].Message);
}

c# lock and listen to CancellationToken

I want to use lock or a similar synchronization to protect a critical section. At the same time I want to listen to a CancellationToken.
Right now I'm using a mutex like this, but mutex doesn't have as good performance. Can I use any of other synchronization classes (including the new .Net 4.0) instead of the mutex?
WaitHandle.WaitAny(new[] { CancelToken.WaitHandle, _mutex});
CancelToken.ThrowIfCancellationRequested();
Take a look at the new .NET 4.0 Framework feature SemaphoreSlim Class. It provides SemaphoreSlim.Wait(CancellationToken) method.
Blocks the current thread until it can enter the SemaphoreSlim, while
observing a CancellationToken
From some point of view using Semaphore in such simple case could be an overhead because initially it was designed to provide an access for multiple threads, but perhaps you might find it useful.
EDIT: The code snippet
CancellationToken token = new CancellationToken();
SemaphoreSlim semaphore = new SemaphoreSlim(1,1);
bool tokenCanceled = false;
try {
try {
// block section entrance for other threads
semaphore.Wait(token);
}
catch (OperationCanceledException) {
// The token was canceled and the semaphore was NOT entered...
tokenCanceled = true;
}
// critical section code
// ...
if (token.IsCancellationRequested)
{
// ...
}
}
finally {
if (!tokenCanceled)
semaphore.Release();
}
private object _lockObject = new object();
lock (_lockObject)
{
// critical section
using (token.Register(() => token.ThrowIfCancellationRequested())
{
// Do something that might need cancelling.
}
}
Calling Cancel() on a token will result in the ThrowIfCancellationRequested() being invoked as that was what is hooked up to the Register callback. You can put whatever cancellation logic you want in here. This approach is great because you can cancel blocking calls by forcing the conditions that will cause the call to complete.
ThrowIfCancellationRequested throws a OperationCanceledException. You need to handle this on the calling thread or your whole process could be brought down. A simple way of doing this is by starting your task using the Task class which will aggregate all the exceptions up for you to handle on the calling thread.
try
{
var t = new Task(() => LongRunningMethod());
t.Start();
t.Wait();
}
catch (AggregateException ex)
{
ex.Handle(x => true); // this effectively swallows any exceptions
}
Some good stuff here covering co-operative cancellation
You can use Monitor.TryEnter with timeout to wait for the lock and check periodically for cancellation.
private bool TryEnterSyncLock(object syncObject)
{
while(!Monitor.TryEnter(syncObject, TimeSpan.FromMilliseconds(100)))
{
if (cts_.IsCancellationRequested)
return false;
}
return true;
}
Note that I would not recommend this in high contention situations as it can impact performance. I would use it as a safety mechanism against deadlocks in case you cannot use SemaphoreSlim as it has different same thread re-entrancy semantics than Monitor.Enter.
After returning true, lock on syncObject has to be released using Monitor.Exit.

Categories

Resources