Два воркера читают один ограниченный канал. Один из них отменяет ожидание. Продюсер успешно записывает сообщение — без исключений.
using System.Threading.Channels;
var queue = Channel.CreateBounded<int>(
new BoundedChannelOptions(1)
{
FullMode = BoundedChannelFullMode.Wait
});
using var cts = new CancellationTokenSource();
var firstRead = queue.Reader.ReadAsync().AsTask();
var firstWorker = Task.Run(async () =>
{
try
{
var item = await firstRead.WaitAsync(cts.Token);
Console.WriteLine($"A: {item}");
}
catch (OperationCanceledException)
{
Console.WriteLine("A: canceled");
}
});
// Дожидаемся, чтобы первый воркер обработал отмену.
cts.Cancel();
await firstWorker;
var secondWorker = Task.Run(async () =>
{
await foreach (var item in queue.Reader.ReadAllAsync())
Console.WriteLine($"B: {item}");
});
await queue.Writer.WriteAsync(42);
queue.Writer.TryComplete();
await secondWorker;
await queue.Reader.Completion;
Console.WriteLine("Finished");
Разберите без запуска:
1. Что выведет программа? Возможны ли разные результаты?
2. Где окажется
42, если ни один воркер его не напечатает?3. Почему
Reader.Completion успешно завершится?4. Чем отличаются эти две записи?
reader.ReadAsync().AsTask().WaitAsync(token)
reader.ReadAsync(token).AsTask()
Усложнение: отмена и запись происходят одновременно. Достаточно ли второй записи, чтобы гарантировать, что сообщение не потеряется?
Предложите протокол остановки: после извлечения сообщение должно быть обработано либо явно сохранено для повторной попытки. Очередь остаётся ограниченной, обработчики могут завершаться с ошибкой.
👇 В какой момент ответственность за сообщение переходит от канала к воркеру?