Reputation: 11
I am newbie to multi threading and wasted couple of days debugging this program with no luck.I am trying to do proof of concept before I go ahead and implement this for production.
I have a list of custom objects. Their properties are T of type Task and Timeout of type int. I am trying to lunch multiple the task in parrallel and terminate the task if it times out. For demonstration purposes, I did create two simple tasks which they do simple things
public class Program
{
public static void Main(string[] args)
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken cancellationToken = cancellationTokenSource.Token;
List<MyItem> myItems = new List<MyItem>();
myItems.Add(createtask1(2000,1000,cancellationToken)); // this task should run for one second....result: should timeout
myItems.Add(createtask2(2000,3000,cancellationToken));// this task should run for two second....result: should NOT timeout
Parallel.ForEach(myItems,(item)=>{
Task task = item.T;
// start the task
task.Start();
Console.WriteLine("waiting for the task with timeout:{0} to finish", item.Timeout);
try{
bool hasNotTimedOut = task.Wait(item.Timeout);
if (hasNotTimedOut)
{
Console.WriteLine("Task with timeout: {0}, has not timed out", item.Timeout);
}
else
{
Console.WriteLine("Task with timeout: {0}, has timed out", item.Timeout);
cancellationTokenSource.Cancel();
Console.WriteLine("Status of the task with timeout: {0} is {1}", item.Timeout,task.Status.ToString());
}
}
catch (AggregateException ex)
{
if (ex.InnerException is OperationCanceledException)
{
Console.WriteLine("Status of the task with timeout: {0} is {1}5", item.Timeout,task.Status.ToString());
}
else
Console.WriteLine(ex);
}
});
// Task.WaitAll(myItems.Select(item=>item.T).ToArray());
Console.WriteLine("End of Main");
}
private static MyItem createtask1(int delayTime, int timeout,CancellationToken cancellationToken)
{
MyItem toReturn = new MyItem();
toReturn.Timeout = timeout;
toReturn.T = new Task(()=>{
Console.WriteLine("Task1 is getting executed with DelayTime:{0}, timeout:{1}",delayTime,timeout);
Task.Delay(delayTime).Wait();
Console.WriteLine("Task1 finished executing with DelayTime:{0}, timeout:{1}",delayTime,timeout);
cancellationToken.ThrowIfCancellationRequested();
},cancellationToken);
return toReturn;
}
private static MyItem createtask2(int delayTime, int timeout,CancellationToken cancellationToken)
{
MyItem toReturn = new MyItem();
toReturn.Timeout = timeout;
toReturn.T = new Task(()=>{
Console.WriteLine("Task2 is getting executed with DelayTime:{0}, timeout:{1}",delayTime,timeout);
Task.Delay(delayTime).Wait();
Console.WriteLine("Task2 finished executing with DelayTime:{0}, timeout:{1}",delayTime,timeout);
cancellationToken.ThrowIfCancellationRequested();
},cancellationToken);
return toReturn;
}
}
public class MyItem{
public Task T{get;set;}
public int Timeout{get;set;}
}
It seems it is trying to cancel the last task, but in my case the first case should be cancelled. My code works perfectly if i dont include the CancellationToken i.e it tells me what task timed out.
Can you please tell me what I am doing wrong
Upvotes: 1
Views: 1799
Reputation: 31
Just because you pass a CancellationToken as an argument to a Task and then cancel the Token, the Task will still not be cancelled. You need to check the Token inside the function, and manually cancel the Task when requested.
A CancellationToken can be passed to Task.Delay()
, which implements this system.
Like so:
private static MyItem createtask1(int delayTime, int timeout, CancellationToken cancellationToken)
{
MyItem toReturn = new MyItem();
toReturn.Timeout = timeout;
toReturn.T = new Task(() => {
Console.WriteLine("Task1 is getting executed with DelayTime:{0}, timeout:{1}", delayTime, timeout);
Task.Delay(delayTime, cancellationToken).Wait();
Console.WriteLine("Task1 finished executing with DelayTime:{0}, timeout:{1}", delayTime, timeout);
cancellationToken.ThrowIfCancellationRequested();
}, cancellationToken);
return toReturn;
}
Also, you don't need cancellationToken.ThrowIfCancellationRequested();
, because waiting for Task.Delay()
throws an exception if it is cancelled.
Upvotes: 1