Stream.ReadAsync(byte buffer, int offset, int count, CancellationToken cancellationToken) does not cancel
domingo, 15 de abril de 2012 08:16
Good day, everyone!
I'm writing an app, that have to read other console app output and have found a nasty problem.
First: StreamReader *Async method do not support CancellationToken. This is not good already, but since I found that Stream have ReadAsync with CancellationToken I decided to implement ReadLineAsync(CancellationToken) myself.
And now I found another, bigger problem, that seems to me to a bug in implementation.
ReadAsync(byte buffer, int offset, int count, CancellationToken cancellationToken) does not cancel until it can read at least one new character.
Consider a reallife situation: I use ReadAsync to get data from a NetworkStream, or in my case from StandardOutput of a console app. It may never ever return next byte, that other app may be hanging, or have some other problem. And I expect, that I can single CancellationTokenSource.Cancel() and have resources from my stream freed. But this does not happed. Cancellation works only between byte reads, so if my console app write something after cancellation, I see the task actually cancelled.
Can this be supported in the future, or do I want to use this technology in the wrong way? Can anyone suggest a working way to cancel Read from a stream?
Todas as Respostas
segunda-feira, 16 de abril de 2012 11:04
Ok I did a little research. I had one thought that this behavior may be the limitation of WinApi. But I checked, and found
CancelIoEx function http://msdn.microsoft.com/en-us/library/windows/desktop/aa363792(v=vs.85).aspx
Which does exactly what I want. Strange, that .Net Stream implementation does not seem to use it.
segunda-feira, 16 de abril de 2012 16:48Moderador
The base Stream class is abstract and doesn't actually know how to read or write anything; that's left up to the derived type. The base implementation of Stream.ReadAsync/WriteAsync do a check for cancellation, and then delegate to the BeginRead/EndRead/BeginWrite/EndWrite methods. NetworkStream currently overrides BeginRead/EndRead/BeginWrite/EndWrite, but it doesn't override ReadAsync/WriteAsync. And since the Begin/End methods have no notion of cancellation, you're getting the behavior from the base stream, which is to check on entry whether cancellation has already been requested, but during the operation a cancellation request isn't noticed. Note that in .NET 4.5 Beta, FileStream does in fact support cancellation during operations, indeed using CancelIoEx.
terça-feira, 17 de abril de 2012 10:58
Very interesting! I checked the type of implementation that is returned from Process.StandardOutput.BaseStream and it is FileStream.
But still it is not cancelling my read request. Of cource, console output is a special file type, maybe it is treated in a special way.
What I actually would like to get with post is to inform developers of the problem, and hopefully get it fixed in the release.
terça-feira, 17 de abril de 2012 14:52ModeradorWith FileStream, it depends on how the FileStream is constructed. If the FileStream is constructed with a parameter that informs it to use async I/O, then it will do so, and the async reads/writes will be cancelable. If you don't specify this, then the FileStream will just end up using the base Stream's implementation of BeginRead/EndRead and BeginWrite/EndWrite, which just end up queuing to the ThreadPool a work item that calls Read or Write, respectively.