Я хотел выполнить ряд задач, выполняемых каждый с таймаутом его собственного.Создание задач с таймаутами
Я заимствовал метод расширения для создания задач с таймаутами здесь http://blogs.msdn.com/b/pfxteam/archive/2011/11/10/10235834.aspx
Так код ниже
public static Task TimeoutAfter(this Task task, int millisecondsTimeout)
{
// Short-circuit #1: infinite timeout or task already completed
if (task.IsCompleted || (millisecondsTimeout == Timeout.Infinite))
{
// Either the task has already completed or timeout will never occur.
// No proxy necessary.
return task;
}
// tcs.Task will be returned as a proxy to the caller
TaskCompletionSource<VoidTypeStruct> tcs = new TaskCompletionSource<VoidTypeStruct>();
// Short-circuit #2: zero timeout
if (millisecondsTimeout == 0)
{
// We've already timed out.
tcs.SetException(new TimeoutException());
return tcs.Task;
}
// Set up a timer to complete after the specified timeout period
Timer timer = new Timer(state =>
{
// Recover your state information
var myTcs = (TaskCompletionSource<VoidTypeStruct>)state;
// Fault our proxy with a TimeoutException
myTcs.TrySetException(new TimeoutException());
}, tcs, millisecondsTimeout, Timeout.Infinite);
// Wire up the logic for what happens when source task completes
task.ContinueWith(antecedent =>
{
timer.Dispose(); // Cancel the timer
MarshalTaskResults(antecedent, tcs); // Marshal results to proxy
},
CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
return tcs.Task;
}
public class Program
{
private static List<int> Output = new List<int>();
private static Random _random = new Random();
public static void LongRunningTask(string message)
{
Console.WriteLine(message);
Console.WriteLine("Managed thread Id " + Thread.CurrentThread.ManagedThreadId);
//Simulate a long running task
Thread.Sleep(TimeSpan.FromSeconds(3));
var number = _random.Next();
Console.WriteLine("Adding " + number);
Output.Add(number);
}
public static void Main(string[] args)
{
var tasks = new List<Task>();
var t1 = Task.Factory.StartNew(_ => LongRunningTask("Entering task1"),TaskCreationOptions.AttachedToParent).TimeoutAfter(10);
var t2 = Task.Factory.StartNew(_ => LongRunningTask("Entering task2"),TaskCreationOptions.AttachedToParent);
var t3 = Task.Factory.StartNew(_ => LongRunningTask("Entering task3"),TaskCreationOptions.AttachedToParent);
tasks.Add(t1);
tasks.Add(t2);
tasks.Add(t3);
try
{
Task.WaitAll(tasks.ToArray());
}
catch (Exception ex)
{
Console.WriteLine("There was an exception");
Console.WriteLine(ex.InnerException.Message);
}
Console.WriteLine("Output :");
Output.ForEach(_ => Console.WriteLine(_));
Console.ReadLine();
}
}
the output
Entering task1
Managed thread Id 10
Entering task2
Managed thread Id 11
Entering task3
Managed thread Id 14
Adding 453738994
Adding 156432981
Adding 1340619865
There was an exception
The operation has timed out.
Output :
453738994
156432981
1340619865
теперь, что я не могу понять, почему это до сих пор t1 отделку даже хотя я указал тайм-аут и возникло исключение таймаута.
Я использую .NET 4.
Edit:
Обеспечение того, что истекло задача не делать ничего после периода таймаута т.е. отмены задачи в целом.
public class Program
{
private static List<int> Output = new List<int>();
private static Random _random = new Random();
public static int LongRunningTask(string message)
{
Console.WriteLine(message);
Console.WriteLine("Managed thread Id " + Thread.CurrentThread.ManagedThreadId);
//Simulate a long running task
Thread.Sleep(TimeSpan.FromSeconds(2));
var number = _random.Next();
Console.WriteLine("Adding " + number + " From thread - " + Thread.CurrentThread.ManagedThreadId);
return number;
}
public static void Main(string[] args)
{
Console.WriteLine("In Main");
Console.WriteLine("Managed thread Id " + Thread.CurrentThread.ManagedThreadId);
var cts = new CancellationTokenSource();
var tasks = new List<Task>();
var t1 = Task.Factory.StartNew(_ => LongRunningTask("Entering task1"), TaskCreationOptions.AttachedToParent)
.ContinueWith(_ => Output.Add(_.Result),cts.Token)
.TimeoutAfter(1000);
var t2 = Task.Factory.StartNew(_ => LongRunningTask("Entering task2"), TaskCreationOptions.AttachedToParent)
.ContinueWith(_ => Output.Add(_.Result));
var t3 = Task.Factory.StartNew(_ => LongRunningTask("Entering task3"), TaskCreationOptions.AttachedToParent)
.ContinueWith(_ => Output.Add(_.Result));
tasks.Add(t1);
tasks.Add(t2);
tasks.Add(t3);
try
{
Task.WaitAll(tasks.ToArray());
}
catch (Exception ex)
{
Console.WriteLine("There was an exception");
Console.WriteLine(ex.InnerException.Message);
cts.Cancel();
}
Console.WriteLine("Output :");
Output.ForEach(_ => Console.WriteLine(_));
Console.ReadLine();
}
}
Выход:
In Main
Managed thread Id 9
Entering task1
Managed thread Id 10
Entering task2
Managed thread Id 11
Entering task3
Managed thread Id 13
Adding 1141027730 From thread - 10
Adding 1856518562 From thread - 13
Adding 1856518562 From thread - 11
There was an exception
The operation has timed out.
Output :
1141027730
1856518562
1856518562
Как я могу сказать задачу, чтобы остановить выполнение после того, как тайм-аут произошел, так что он ничего не добавляет к выходу в то время как работает в фоновом режиме. Поставка его с использованием источника токена отмены, а затем его отмена не работает. –
В коде только 'Task.WaitAll' перебрасывает TimoutException, все задачи уже завершены и' cts.Cancel() 'не имеет значения. Поместите 'cts.Cancel()' перед 'Task.WaitAll', и задача будет принудительной. – GSerjo
Это отменит задачу независимо от тайм-аута. Поведение, которое я хочу, - это отменить задачу в случае тайм-аута или исключения. –