-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Description
The standard io streams on Process are FileStreams pointing to the underlying anonymous pipes which on windows do not support async IO (see this issue). As a result, canceling hung reads/writes with CancellationToken does not work reliably.
This is frustrating because process streams operations are actually fairly likely to hang, either because the buffer fills up for standard input or because the underlying process is hanging/not writing to that stream. It is also frustrating that cancellation works on Linux but not Windows, leading to different behaviors between platforms.
I think this scenario could be supported via the CancelSynchronousIo function in Windows; the async IO operations on sync FileStreams are async-over-sync so it should be possible to cancel the IO operation on the threadpool thread that is running it.
Reproduction Steps
async Task Main()
{
var process = new Process { StartInfo = { } };
process.StartInfo.FileName = "cmd";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.UseShellExecute = false;
process.Start();
var t = Task.Run(async () =>
{
while (true)
{
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
if (await process.StandardOutput.BaseStream.ReadAsync(new byte[10], 0, 10, cts.Token) == 0) { break; }
}
});
Console.WriteLine(t.Wait(5000)); // false
process.Kill();
await t; // succeeds
}
Expected behavior
t.Wait(5000); should throw after 1s when the task becomes canceled.
Actual behavior
Cancellation never triggers; once the process is killed after 5s the ReadAsync call returns 0 bytes and completes successfully.
Regression?
No
Known Workarounds
You can avoid calling ReadAsync and instead call Read and use CancelSynchronousIo yourself.
Configuration
Windows 10 x64 .NET 6
Other information
No response