Фон
У меня есть Service
абстракция.Каждый сервис имеет свой собственный WorkItem
.WorkItem может начать с некоторых данных.Услуга ограничивает время исполнения WorkItem
.Допустим, один рабочий элемент может занять до 60 секунд.После этого Service
должен убить его.
Этот код перенесен из Standard .NET Framework , я создал объект Thread
, который запускает метод Start(model)
.Тогда код был что-то вроде:
Thread t = new Thread(workItem.Start, model);
t.start();
if (!t.Join(TimeSpan.FromSeconds(60)))
t.Abort();
Thread.Abort
выдавал исключение для запущенного потока, что приводило к немедленной остановке.
Теперь, Я переместил код в ядро dotnet - как вы, возможно, знаете, когда вы звоните Thread.Abort()
, вы получаете следующее сообщение:
System.PlatformNotSupportedException: Thread abort is not supported on this platform.
at System.Threading.Thread.Abort()
at ...
Цель
Я хочу ограничить время выполнения WorkItem
определенным количеством времени.Обратите внимание, что это ограничение должно работать и в том случае, если вы запускаете строку кода следующим образом:
Thread.sleep(61000); // 61 seconds. should be stop after 60 seconds.
Progress
В мире ядра dotnet кажется, что оно идет к решению, связанному с Task
.Итак, я подумал использовать CancellationToken
.Но кажется невозможным наблюдать за событием "Cacneled" и немедленно остановиться.Примеры, которые я видел, используют циклы while (!canceled)
, которые не могут остановить длинные операции (например, Thread.Sleep(1000000)
.
Вопрос
Как это сделать правильно?
Обновление
Я написал этот пример кода:
public static bool ExecuteWithTimeLimit(TimeSpan timeSpan, Action codeBlock)
{
try
{
Task task = Task.Factory.StartNew(() => codeBlock());
if (!task.Wait(timeSpan))
{
// ABORT HERE!
Console.WriteLine("Time exceeded. Aborted!");
}
return task.IsCompleted;
}
catch (AggregateException ae)
{
throw ae.InnerExceptions[0];
}
}
И этот Main
файл:
public static void Main(string[] args)
{
bool Completed = ExecuteWithTimeLimit(TimeSpan.FromMilliseconds(2000), () =>
{
Console.WriteLine("start");
Thread.Sleep(3000);
Console.WriteLine("end");
});
Console.WriteLine($"Completed={Completed}");
Console.ReadLine();
}
Ожидается: «конец» не будет выводиться на экран. Фактический: «end "напечатано. Есть ли альтернатива, которая может убить Task
?