I am currently working on a piece of software that uses an assembly from a different department.I call a Method from this assembly like this:
using (var connection = (IConnection) Factory.GetObject(typeof (IConnection)))
The code used to work perfectly fine. But for the last few minutes it seemed like my program was doing nothing when I tried to launch it. Pressing pause while debugging showed me it got "stuck" at the line above.My guess is they're just doing some maintenance or something but that's not the point here.
So I though it would be nice to tell the user what went wrong if the program doesn't start. Something simple like
MessageBox.Show("Could not connect", "Connection Error");
And then close the program. My question is:
How do I terminate the execution of a command after a set amount of time and jump somewhere else?My guess would be moving it to a separate thread and then putting the calling thread to sleep for a few seconds after which it disposes of the extra thread if it isn't completed yet. But that seems really dirty to me and there's got to be a better way.
Your question can be separated into two parts:
How to terminate the execution of a command?
The only way is to abort the thread. But don't do it. There is no guaranteed and safe way. There are such methods like Thread.Interrupt and Thread.Abort that can wake up the thread. But they will work only if the thread is in the WaitSleepJoin state and it hangs in managed code.
Seems like you already know it. But once again, if something inside the assembly hangs infinitely the execution of code then the thread is probably "gone". So you are right that the program should be closed.
... jump somewhere else?
Good approach is using of TPL and async model.
Here is an extension method to wrap up any Task and expires after timeout.
public static async Task TimeoutAfter(this Task task, int millisecondsTimeout)
{
if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout)))
await task;
else
throw new TimeoutException();
}
Then use it
try
{
using (var result = await Task.Run(() => (IConnection)Factory.GetObject(typeof(IConnection))).TimeoutAfter(1000))
{
...
}
}
catch (TimeoutException ex)
{
//timeout
}
Here you can find more information
A simple way of doing it without extra libraries or extension methods:
using ( var task = new Task<IConnection>( () => Factory.GetObject( typeof( IConnection ) ) ) )
{
task.Start();
if( !task.Wait( timeoutMilliseconds ) )
{
throw new TimeoutException();
}
IConnection result = task.Result;
}
Task.Wait does what you want, because you can throw an exception if it returns false (task didn't complete in time.)
It's even simpler if you have an Action that doesn't return something:
if ( !Task.Run( action ).Wait( timeoutMilliseconds ) )
{
throw new TimeoutException();
}
Where action is some Action or lambda.
The easiest way to do this, if a native timeout is not implemented, as you mentioned, is a separate thread to load it on. Although this sounds like it'll be really dirty, it's as simple as (using Rx):
Task<IConnection> connectionTask = Observable.Start(() => Factory.GetObject(typeof (IConnection)), Scheduler.Default).Timeout(TimeSpan.FromSeconds(20)).ToTask());
using (var connection = connectionTask.Result)
{
...
}
You can tweak the Scheduler if you don't want it to run on the threadpool. It will throw a TimeoutException if the Factory.GetObject call takes longer than 20 seconds.
You could use CancellationTokenSource to set a timeout on the operation
var timeoutCts = new CancellationTokenSource();
try
{
timeoutCts.CancelAfter(300000); // Cancel after 5 minutes
// ... run your long term operation
}
catch (OperationCanceledException ex)
{
// Handle the timeout
}
Please see this documentation from Microsoft
using System;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
Task t = Task.Run(() =>
{
Random rnd = new Random();
long sum = 0;
int n = 5000000;
for (int ctr = 1; ctr <= n; ctr++)
{
int number = rnd.Next(0, 101);
sum += number;
}
Console.WriteLine("Total: {0:N0}", sum);
Console.WriteLine("Mean: {0:N2}", sum / n);
Console.WriteLine("N: {0:N0}", n);
});
TimeSpan ts = TimeSpan.FromMilliseconds(150);
if (!t.Wait(ts))
Console.WriteLine("The timeout interval elapsed.");
}
}
Related
I need to move from using a synchronous API to async API:
void Client()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
int numAttempts = SendWithRetries();
stopWatch.Stop();
Logging.Log(LoggingLevel.Info, string.Format("time taken {0} ", numEvents, partitionId, stopWatch.Elapsed.TotalSeconds.ToString()));
}
private int SendWithRetries(int numRetries = 3)
{
for (int i = 0; i <= numRetries; i++)
{
try
{
API();
return i;
}
catch (Exception e)
{
if (i == numRetries)
{
throw;
}
}
}
return -1;
}
Now to move to async API, I gather from internet that I need to replace API with
await APIAsync()
I am a little confused on this. When I add await, it would force the main thread to wait for completion of APIAsync How is that different from the synchronous call?
What if I do the following change and continue calling API() within SendWithRetries method:
void Client()
{
Task newTask =
System.Threading.Tasks.Task.Run(() => {
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
int numAttempts = SendWithRetries();
stopWatch.Stop();
Logging.Log(LoggingLevel.Info, string.Format("### time taken {0} ", numEvents, partitionId, stopWatch.Elapsed.TotalSeconds.ToString()));
});
newTask.Wait();
}
Why is using the async method with await better than the above approach?
Also, whats wrong with the following:
private int SendWithRetries(int numRetries = 3)
{
for (int i = 0; i <= numRetries; i++)
{
try
{
APIAsync();
return i;
}
catch (Exception e)
{
if (i == numRetries)
{
throw;
}
}
}
return -1;
}
How is that different from the synchronous call?
Asynchronous code doesn't block the calling thread.
Why is using the async method with await better than the above approach?
That approach moves the blocking to a thread pool thread (Task.Run). Asynchronous code doesn't block a thread pool thread.
Also, whats wrong with the following
Since the code ignores the returned Task, the code can never know when the API call completes, or whether it had an error.
More information:
Async and await
Async best practices
The await keyword allows the application to wait without becoming non-responsive. The user will be able to continue interacting with the application, while the awaited operation is running in the background. When the operation completes, the code after the await will execute, by default in the UI thread.
You may need to restrict the user from certain interactions for the duration of the awaited operation. Some buttons or menu options may better become disabled, so that the user cannot initiate multiple asynchronous operations, and cause resources starvation or other problems.
I've the following code:
static void Main(string[] args)
{
IEnumerable<int> threadsIds = Enumerable.Range(1, 1000);
DateTime globalStart = DateTime.Now;
Console.WriteLine("{0:s.fff} Starting tasks", globalStart);
Parallel.ForEach(threadsIds, (threadsId) =>
{
DateTime taskStart = DateTime.Now;
const int sleepDuration = 1000;
Console.WriteLine("{1:s.fff} Starting task {0}, sleeping for {2}", threadsId, taskStart, sleepDuration);
Thread.Sleep(sleepDuration);
DateTime taskFinish = DateTime.Now;
Console.WriteLine("{1:s.fff} Ending task {0}, task duration {2}", threadsId, taskFinish, taskFinish- taskStart);
});
DateTime globalFinish= DateTime.Now;
Console.WriteLine("{0:s.fff} Tasks finished. Total duration: {1}", globalFinish, globalFinish-globalStart);
Console.ReadLine();
}
Currently when I run it, it takes ~60seconds to run it. For what I understand, it's because .Net doesn't create one thread per task but some threads for all the Tasks, and when I do the Thread.Sleep, I prevent this thread to execute some other tasks.
In my real case, I've some work to do in parallel, and in case of failure, I've to wait some amount of time before trying again.
I'm looking something else than the Thread.Sleep, that would allow other tasks to run during the "sleep time" of other tasks.
Unfortunately, I'm currently running .Net 4, which prevent me to use async and await(which I guess could have helped me in this case.
Ps, I got the same results by:
putting Task.Delay(sleepDuration).Wait()
Not using Parallel.Foreach, but a foreach with a Task.Factory.StartNew
Ps2, I know that I can do my real case differently, but I'm very interessted to understand how it could be achieved that way.
You are on the right path. Task.Delay(timespan) is the solution for your problem. Since you cannot use async/await, you have to write a bit more code to achieve the desired result.
Think about using Task.ContinueWith() method, for example:
Task.Run(() => { /* code before Thread.Sleep */ })
.ContinueWith(task => Task.Delay(sleepDuration)
.ContinueWith(task2 => { /* code after Thread.Sleep */ }));
Also you will need create a class to make local method variables accessible across subtasks.
If you want to create a task that will run polling every second some condition, you could try the following code:
Task PollTask(Func<bool> condition)
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
PollTaskImpl(tcs, condition);
return tcs.Task;
}
void PollTaskImpl(TaskCompletionSource<bool> tcs, Func<bool> condition)
{
if (condition())
tcs.SetResult(true);
else
Task.Delay(1000).ContinueWith(_ => PollTaskImpl(tcs, condition));
}
Don't worry about creating new task every second - ContinueWith and async/await methods do the same thing internally.
I am using Async await with Task.Factory method.
public async Task<JobDto> ProcessJob(JobDto jobTask)
{
try
{
var T = Task.Factory.StartNew(() =>
{
JobWorker jobWorker = new JobWorker();
jobWorker.Execute(jobTask);
});
await T;
}
This method I am calling inside a loop like this
for(int i=0; i < jobList.Count(); i++)
{
tasks[i] = ProcessJob(jobList[i]);
}
What I notice is that new tasks opens up inside Process explorer and they also start working (based on log file). however out of 10 sometimes 8 or sometimes 7 finishes. Rest of them just never come back.
why would that be happening ?
Are they timing out ? Where can I set timeout for my tasks ?
UPDATE
Basically above, I would like each Task to start running as soon as they are called and wait for the response on AWAIT T keyword. I am assuming here that once they finish each of them will come back at Await T and do the next action. I am alraedy seeing this result for 7 out of 10 tasks but 3 of them are not coming back.
Thanks
It is hard to say what the issues is without the rest if the code, but you code can be simplified by making ProcessJob synchronous and then calling Task.Run with it.
public JobDto ProcessJob(JobDto jobTask)
{
JobWorker jobWorker = new JobWorker();
return jobWorker.Execute(jobTask);
}
Start tasks and wait for all tasks to finish. Prefer using Task.Run rather than Task.Factory.StartNew as it provides more favourable defaults for pushing work to the background. See here.
for(int i=0; i < jobList.Count(); i++)
{
tasks[i] = Task.Run(() => ProcessJob(jobList[i]));
}
try
{
await Task.WhenAll(tasks);
}
catch(Exception ex)
{
// handle exception
}
First, let's make a reproducible version of your code. This is NOT the best way to achieve what you are doing, but to show you what is happening in your code!
I'll keep the code almost same as your code, except I'll use simple int rather than your JobDto and on completion of the job Execute() I'll write in a file that we can verify later. Here's the code
public class SomeMainClass
{
public void StartProcessing()
{
var jobList = Enumerable.Range(1, 10).ToArray();
var tasks = new Task[10];
//[1] start 10 jobs, one-by-one
for (int i = 0; i < jobList.Count(); i++)
{
tasks[i] = ProcessJob(jobList[i]);
}
//[4] here we have 10 awaitable Task in tasks
//[5] do all other unrelated operations
Thread.Sleep(1500); //assume it works for 1.5 sec
// Task.WaitAll(tasks); //[6] wait for tasks to complete
// The PROCESS IS COMPLETE here
}
public async Task ProcessJob(int jobTask)
{
try
{
//[2] start job in a ThreadPool, Background thread
var T = Task.Factory.StartNew(() =>
{
JobWorker jobWorker = new JobWorker();
jobWorker.Execute(jobTask);
});
//[3] await here will keep context of calling thread
await T; //... and release the calling thread
}
catch (Exception) { /*handle*/ }
}
}
public class JobWorker
{
static object locker = new object();
const string _file = #"C:\YourDirectory\out.txt";
public void Execute(int jobTask) //on complete, writes in file
{
Thread.Sleep(500); //let's assume does something for 0.5 sec
lock(locker)
{
File.AppendAllText(_file,
Environment.NewLine + "Writing the value-" + jobTask);
}
}
}
After running just the StartProcessing(), this is what I get in the file
Writing the value-4
Writing the value-2
Writing the value-3
Writing the value-1
Writing the value-6
Writing the value-7
Writing the value-8
Writing the value-5
So, 8/10 jobs has completed. Obviously, every time you run this, the number and order might change. But, the point is, all the jobs did not complete!
Now, if I un-comment the step [6] Task.WaitAll(tasks);, this is what I get in my file
Writing the value-2
Writing the value-3
Writing the value-4
Writing the value-1
Writing the value-5
Writing the value-7
Writing the value-8
Writing the value-6
Writing the value-9
Writing the value-10
So, all my jobs completed here!
Why the code is behaving like this, is already explained in the code-comments. The main thing to note is, your tasks run in ThreadPool based Background threads. So, if you do not wait for them, they will be killed when the MAIN process ends and the main thread exits!!
If you still don't want to await the tasks there, you can return the list of tasks from this first method and await the tasks at the very end of the process, something like this
public Task[] StartProcessing()
{
...
for (int i = 0; i < jobList.Count(); i++)
{
tasks[i] = ProcessJob(jobList[i]);
}
...
return tasks;
}
//in the MAIN METHOD of your application/process
var tasks = new SomeMainClass().StartProcessing();
// do all other stuffs here, and just at the end of process
Task.WaitAll(tasks);
Hope this clears all confusion.
It's possible your code is swallowing exceptions. I would add a ContineWith call to the end of the part of the code that starts the new task. Something like this untested code:
var T = Task.Factory.StartNew(() =>
{
JobWorker jobWorker = new JobWorker();
jobWorker.Execute(jobTask);
}).ContinueWith(tsk =>
{
var flattenedException = tsk.Exception.Flatten();
Console.Log("Exception! " + flattenedException);
return true;
});
},TaskContinuationOptions.OnlyOnFaulted); //Only call if task is faulted
Another possibility is that something in one of the tasks is timing out (like you mentioned) or deadlocking. To track down whether a timeout (or maybe deadlock) is the root cause, you could add some timeout logic (as described in this SO answer):
int timeout = 1000; //set to something much greater than the time it should take your task to complete (at least for testing)
var task = TheMethodWhichWrapsYourAsyncLogic(cancellationToken);
if (await Task.WhenAny(task, Task.Delay(timeout, cancellationToken)) == task)
{
// Task completed within timeout.
// Consider that the task may have faulted or been canceled.
// We re-await the task so that any exceptions/cancellation is rethrown.
await task;
}
else
{
// timeout/cancellation logic
}
Check out the documentation on exception handling in the TPL on MSDN.
I've got a problem. I'm writing a benchmark and I have a function than is either done in 2 seconds or after ~5 minutes(depending on the input data). And I would like to stop that function if it's executed for more than 3 seconds...
How can I do it?
Thanks a lot!
Well..., I had the same question, and after reading all the answers here and the referred blogs, I settled for this,
It Lets me execute any block of code with a time limit, Declare the wrapper method
public static bool ExecuteWithTimeLimit(TimeSpan timeSpan, Action codeBlock)
{
try
{
Task task = Task.Factory.StartNew(() => codeBlock());
task.Wait(timeSpan);
return task.IsCompleted;
}
catch (AggregateException ae)
{
throw ae.InnerExceptions[0];
}
}
And use that to wrap any block of code like this
// code here
bool Completed = ExecuteWithTimeLimit(TimeSpan.FromMilliseconds(1000), () =>
{
//
// Write your time bounded code here
//
});
//More code
The best way would be that your function can check its execution time often enough to decide to stop it it takes too long.
If this is not the case, then run the function in a separate thread. In your main thread start a 3 seconds timer. When timer elapses, kill the separate thread using Thread.Abort() (of course unless the function is already over). See sample code and preacuations of usage in the function docs.
The best way in C# to stop function in middle is the return keyword in function, but how do I know when to use the return keyword to stop the function in middle, after it lasts at least 3 seconds? The Stopwatch class from System.Diagnostics is the answer. This complicated function that lasts between 2 seconds to 5 minutes (depending on the input data) logically uses many loops, and maybe even recursion, so my solution for you is that, at the first line code of that function, create an instance of Stopwatch using System.Diagnostics with the new keyword, start it by calling the Start() function of the Stopwatch class, and in for each loop and loop, at the beginning, add the following code:
if (stopwatch.ElapsedMilliseconds >= 3000) {
stopwatch.Stop();
// or
stopwatch.Reset();
return;
}
(tip: you can type it with hands once, copy it Ctrl+C, and then just paste it Ctrl+V). If that function uses recursion, in order to save memory, make the Stopwatch global instance rather than creating it as local instance at first, and start it if it does not running at the beginning of the code. You can know that with the IsRunning of the Stopwatch class. After that ask if elapsed time is more than 3 seconds, and if yes (true) stop or reset the Stopwatch, and use the return keyword to stop the recursion loop, very good start in function, if your function lasts long time due mainly recursion more than loops. That it is. As you can see, it is very simple, and I tested this solution, and the results showed that it works! Try it yourself!
private static int LongRunningMethod()
{
var r = new Random();
var randomNumber = r.Next(1, 10);
var delayInMilliseconds = randomNumber * 1000;
Task.Delay(delayInMilliseconds).Wait();
return randomNumber;
}
And
var task = Task.Run(() =>
{
return LongRunningMethod();
});
bool isCompletedSuccessfully = task.Wait(TimeSpan.FromMilliseconds(3000));
if (isCompletedSuccessfully)
{
return task.Result;
}
else
{
throw new TimeoutException("The function has taken longer than the maximum time allowed.");
}
it work for me!
Source: https://jeremylindsayni.wordpress.com/2016/05/28/how-to-set-a-maximum-time-to-allow-a-c-function-to-run-for/
You can use the fork/join pattern, in the Task Parallel Library this is implemented with Task.WaitAll()
using System.Threading.Tasks;
void CutoffAfterThreeSeconds() {
// start function on seperate thread
CancellationTokenSource cts = new CancellationTokenSource();
Task loop = Task.Factory.StartNew(() => Loop(cts.Token));
// wait for max 3 seconds
if(Task.WaitAll(new Task[]{loop}, 3000)){
// Loop finished withion 3 seconds
} else {
// it did not finish within 3 seconds
cts.Cancel();
}
}
// this one takes forever
void Loop() {
while (!ct.IsCancellationRequested) {
// your loop goes here
}
Console.WriteLine("Got Cancelled");
}
This will start the other task on a seperate thread, and then wait for 3000 milliseconds for it to finish. If it did finish within the timeout, it return true, else false so you can use that to decide what to do next.
You can use a CancellationToken to communicate to the other thread that it result is no longer needed so it can stop gracefully.
Regards Gert-Jan
Run this function in thread and kill it after 3 seconds or check elapsed time inside this function(I think it's loop there).
Use an OS callbacks with a hi performance counter, then kill your thread, if exists
It is possible to execute a function in a separate thread and limit its execution with Thread.Join(millisecondsTimeout):
using System.Threading;
Thread workThread = new Thread(DoFunc);
workThread.Start(param);
if (!workThread.Join(3000))
{
// DoFunc() took longer than 3 seconds. Thread was aborted
}
private void DoFunc(object param)
{
// do some long work
}
Since C# and .net framework are not real-time environments, you can't guarantee even the 3 seconds count. Even if you were to get close to that, you would still have to call the
if(timeSpan > TimeSpan.FromSeconds(3) then goto endindentifier; before every other call in the method.
All this is just wrong so no, there is just no reliable way to do it from what I know.
Although you can try this solution
https://web.archive.org/web/20140222210133/http://kossovsky.net/index.php/2009/07/csharp-how-to-limit-method-execution-time
but I just wouldn't do such things in .net application.
From what I've read about Tasks, the following code should cancel the currently executing task without throwing an exception. I was under the impression that the whole point of task cancellation was to politely "ask" the task to stop without aborting threads.
The output from the following program is:
Dumping exception
[OperationCanceledException]
Cancelling and returning last calculated prime.
I am trying to avoid any exceptions when cancelling. How can I accomplish this?
void Main()
{
var cancellationToken = new CancellationTokenSource();
var task = new Task<int>(() => {
return CalculatePrime(cancellationToken.Token, 10000);
}, cancellationToken.Token);
try
{
task.Start();
Thread.Sleep(100);
cancellationToken.Cancel();
task.Wait(cancellationToken.Token);
}
catch (Exception e)
{
Console.WriteLine("Dumping exception");
e.Dump();
}
}
int CalculatePrime(CancellationToken cancelToken, object digits)
{
int factor;
int lastPrime = 0;
int c = (int)digits;
for (int num = 2; num < c; num++)
{
bool isprime = true;
factor = 0;
if (cancelToken.IsCancellationRequested)
{
Console.WriteLine ("Cancelling and returning last calculated prime.");
//cancelToken.ThrowIfCancellationRequested();
return lastPrime;
}
// see if num is evenly divisible
for (int i = 2; i <= num/2; i++)
{
if ((num % i) == 0)
{
// num is evenly divisible -- not prime
isprime = false;
factor = i;
}
}
if (isprime)
{
lastPrime = num;
}
}
return lastPrime;
}
I am trying to avoid any exceptions when cancelling.
You shouldn't do that.
Throwing OperationCanceledException is the idiomatic way that "the method you called was cancelled" is expressed in TPL. Don't fight against that - just expect it.
It's a good thing, because it means that when you've got multiple operations using the same cancellation token, you don't need to pepper your code at every level with checks to see whether or not the method you've just called has actually completed normally or whether it's returned due to cancellation. You could use CancellationToken.IsCancellationRequested everywhere, but it'll make your code a lot less elegant in the long run.
Note that there are two pieces of code in your example which are throwing an exception - one within the task itself:
cancelToken.ThrowIfCancellationRequested()
and one where you wait for the task to complete:
task.Wait(cancellationToken.Token);
I don't think you really want to be passing the cancellation token into the task.Wait call, to be honest... that allows other code to cancel your waiting. Given that you know you've just cancelled that token, it's pointless - it's bound to throw an exception, whether the task has actually noticed the cancellation yet or not. Options:
Use a different cancellation token (so that other code can cancel your wait independently)
Use a time-out
Just wait for as long as it takes
You are explicitly throwing an Exception on this line:
cancelToken.ThrowIfCancellationRequested();
If you want to gracefully exit the task, then you simply need to get rid of that line.
Typically people use this as a control mechanism to ensure the current processing gets aborted without potentially running any extra code. Also, there is no need to check for cancellation when calling ThrowIfCancellationRequested() since it is functionally equivalent to:
if (token.IsCancellationRequested)
throw new OperationCanceledException(token);
When using ThrowIfCancellationRequested() your Task might look more like this:
int CalculatePrime(CancellationToken cancelToken, object digits) {
try{
while(true){
cancelToken.ThrowIfCancellationRequested();
//Long operation here...
}
}
finally{
//Do some cleanup
}
}
Also, Task.Wait(CancellationToken) will throw an exception if the token was cancelled. To use this method, you will need to wrap your Wait call in a Try...Catch block.
MSDN: How to Cancel a Task
Some of the above answers read as if ThrowIfCancellationRequested() would be an option. It is not in this case, because you won't get your resulting last prime. The idiomatic way that "the method you called was cancelled" is defined for cases when canceling means throwing away any (intermediate) results. If your definition of cancelling is "stop computation and return the last intermediate result" you already left that way.
Discussing the benefits especially in terms of runtime is also quite misleading:
The implemented algorithm sucks at runtime. Even a highly optimized cancellation will not do any good.
The easiest optimization would be to unroll this loop and skip some unneccessary cycles:
for(i=2; i <= num/2; i++) {
if((num % i) == 0) {
// num is evenly divisible -- not prime
isprime = false;
factor = i;
}
}
You can
save (num/2)-1 cycles for every even number, which is slightly less than 50% overall (unrolling),
save (num/2)-square_root_of(num) cycles for every prime (choose bound according to math of smallest prime factor),
save at least that much for every non-prime, expect much more savings, e.g. num = 999 finishes with 1 cycle instead of 499 (break, if answer is found) and
save another 50% of cycles, which is of course 25% overall (choose step according to math of primes, unrolling handles the special case 2).
That accounts to saving a guaranteed minimum of 75% (rough estimation: 90%) of cycles in the inner loop, just by replacing it with:
if ((num % 2) == 0) {
isprime = false;
factor = 2;
} else {
for(i=3; i <= (int)Math.sqrt(num); i+=2) {
if((num % i) == 0) {
// num is evenly divisible -- not prime
isprime = false;
factor = i;
break;
}
}
}
There are much faster algorithms (which I won't discuss because I'm far enough off-topic) but this optimization is quite easy and still proves my point:
Don't worry about micro-optimizing runtime when your algorithm is this far from optimal.
Another note about the benefit of using ThrowIfCancellationRequested rather than IsCancellationRequested: I've found that when needing to use ContinueWith with a continuation option of TaskContinuationOptions.OnlyOnCanceled, IsCancellationRequested will not cause the conditioned ContinueWith to fire. ThrowIfCancellationRequested, however, will set the Canceled condition of the task, causing the ContinueWith to fire.
Note: This is only true when the task is already running and not when the task is starting. This is why I added a Thread.Sleep() between the start and cancellation.
CancellationTokenSource cts = new CancellationTokenSource();
Task task1 = new Task(() => {
while(true){
if(cts.Token.IsCancellationRequested)
break;
}
}, cts.Token);
task1.ContinueWith((ant) => {
// Perform task1 post-cancellation logic.
// This will NOT fire when calling cst.Cancel().
}
Task task2 = new Task(() => {
while(true){
cts.Token.ThrowIfCancellationRequested();
}
}, cts.Token);
task2.ContinueWith((ant) => {
// Perform task2 post-cancellation logic.
// This will fire when calling cst.Cancel().
}
task1.Start();
task2.Start();
Thread.Sleep(3000);
cts.Cancel();
You have two things listening to the token, the calculate prime method and also the Task instance named task. The calculate prime method should return gracefully, but task gets cancelled while it is still running so it throws. When you construct task don't bother giving it the token.