TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.77K subscribers
Post #221 467
День сто восемьдесят четвёртый. #ЗаметкиНаПолях
Многопоточность.
4. Задания. Начало
Проблема с асинхронными вычислениями, запущенными с помощью метода ThreadPool.QueueUserWorkItem() состоит в том, что отсутствует встроенный механизм, позволяющий узнать о завершении операции и получить возвращаемое значение. Для решения этой проблемы используются задания. Следующие вызовы асинхронных операций аналогичны:
ThreadPool.QueueUserWorkItem(Compute, 5);
new Task(Compute, 5).Start();
Объекту Task передаётся делегат Action или Action<object> (в последнем случае следует также передать аргумент метода, как в примере выше). При желании также можно передать структуру CancellationToken для отмены задания. Допустим, метод Calc принимает целое число и производит вычисления. Тогда запустить его в новом задании можно следующим образом:
var t = new Task<int>((n) => Calc((int)n), 10000);
t.Start();
t.Wait();
Console.WriteLine($"Результат: " + t.Result);
Console.ReadLine();
Поток запускает задание и дожидается его выполнения при вызове метода Wait или свойства Result. При этом само задание может выполниться как в новом потоке (тогда поток, вызвавший метод Wait, блокируется), либо в том же потоке.

Отмена задания
Для отмены задания можно воспользоваться объектом CancellationTokenSource (см. https://t.me/NetDeveloperDiary/219 ). Однако, в отличие от обычной асинхронной операции, для отмены задания нужно обратиться не к свойству IsCancellationRequested, а вызывать метод ThrowIfCancellationRequested() токена отмены. Это приводит к исключению OperationCancelledException, которое нужно перехватить в вызывающем коде. Причина в том, что задания возвращают результат. Поэтому, чтобы отличить законченное задание от незаконченного, используется исключение.
private static int Calc(CancellationToken ct, int n)
{
…
ct.ThrowIfCancellationRequested();
…
}

var cts = new CancellationTokenSource();
var t = new Task<int>(() => Calc(cts.Token, 10000), cts.Token);
t.Start();

// вызывается асинхронно
// к этому моменту задание может быть уже выполнено
cts.Cancel();

try
{
Console.WriteLine($"Результат: {t.Result}");
}
catch(AggregateException ex)
{
ex.Handle(x => x is OperationCanceledException);
Console.WriteLine("Операция отменена");
}
Все необработанные исключения, возникающие в задании, проглатываются в исполняющем потоке и сохраняются в коллекции InnerExceptions объекта AggregateException. Поэтому в вызывающем коде перехватывается именно исключение типа AggregateException. Далее с помощью метода Handle() можно отметить нужные нам исключения, как обработанные. В данном случае мы считаем все исключения типа OperationCanceledException обработанными. Если в коллекции после вызова метода Handle останутся необработанные исключения, они попадут в новый объект AggregateException.

Продолжение следует…

Источник: Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 26.
More from @netdeveloperdiary
  1. Oct 10, 2026День 2810. #ЧтоНовенького #VSCode Более Быстрый и Лёгкий C# Dev Kit Мы, разработчики, люби…
  2. Oct 9, 2026День 2809. #Карьера 5 Навыков, Которые Помогут Быстрее Стать Сеньором. Окончание Начало 3.…
  3. Oct 8, 2026День 2808. #Карьера 5 Навыков, Которые Помогут Быстрее Стать Сеньором. Начало В ИТ есть се…
  4. Oct 7, 2026День 2807. #ЗаметкиНаПолях Типы Коллекций в .NET, Которые Стоит Попробовать. Окончание Нач…
  5. Oct 6, 2026🦈 Открытое собеседование на Middle C# | 6 октября, 19:00 МСК Приглашаем на открытое собес…
  6. Oct 6, 2026День 2806. #ЗаметкиНаПолях Типы Коллекций в .NET, Которые Стоит Попробовать. Начало Больши…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →