Description
Under profiling it appears as if BoundedChannel may leak cancellation callbacks when used in this manner:
var channel = Channel.CreateBounded<bool>(1);
while (true)
{
using var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(100));
try
{
await channel.Reader.ReadAsync(cts.Token);
}
catch (OperationCanceledException)
{
}
}
Firstly, is this an intended use case? We have a long-running Channel that multiple readers may attempt to read from (these readers may timeout and cancel their CancellationToken as they disconnect, the 100ms timeout with CTS is to simulate this faster).
If this is an intended use case it looks like _registration
in AsyncOperation ctor is not disposed when cancellation path is taken? I see that TrySetResult()
and TrySetException()
both call UnregisterCancellation()
but not TrySetCanceled()
, though I am unsure if my understanding of this is correct.
In addition to this (or perhaps as a result of it) it seems like OperationCanceledExceptions are accumulated via ExceptionDispatchInfo and a reference back to Deque.