-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Hi.
After some experimentation, it seems to me that unlike NamedPipeClientStream
, AnonymousPipeClientStream
(or AnonymousPipeServerStream
for that matter) does not support cancellation (because there's no way to open the pipe in async mode and so Stream.ReadAsync
is used instead of PipeStream.ReadAsyncCore
). This is a little painful because it means there's no way to "unblock" a pending read or write on that stream when the stream contains no data.
Here's a simple repro that shows what I'm trying to do. It works for named pipes, but not for anonymous ones:
NamedPipeServerStream source = new NamedPipeServerStream("pipe-test", PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
NamedPipeClientStream destination = new NamedPipeClientStream(".", "pipe-test", PipeDirection.In, PipeOptions.Asynchronous);
await destination.ConnectAsync();
CancellationTokenSource cancellationSource = new CancellationTokenSource();
byte[] buffer = new byte[10];
Task<int> readTask = destination.ReadAsync(buffer, 0, buffer.Length, cancellationSource.Token);
// Right now, readTask is blocked waiting for data.
Task timeout = Task.Delay(TimeSpan.FromSeconds(1));
Task winner = await Task.WhenAny(readTask, timeout);
Assert.Equal(timeout, winner);
cancellationSource.Cancel();
// readTask will now fault with TaskCanceledException
timeout = Task.Delay(TimeSpan.FromSeconds(5));
winner = await Task.WhenAny(readTask, timeout);
Assert.Equal(readTask, winner);
// Prove that it was canceled via the correct CancellationToken
TaskCanceledException cancelled = await Assert.ThrowsAsync<TaskCanceledException>(() => readTask);
Assert.Equal(cancellationSource.Token, cancelled.CancellationToken);
Is this by design, or simply something nobody has gotten around to, yet? Because it looks like it should be possible to implement by constructing the base PipeStream
with isAsync: true
to use the correct code-path.