Stream.ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) does not cancel
-
15 เมษายน 2555 8: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?
ตอบทั้งหมด
-
16 เมษายน 2555 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.
-
16 เมษายน 2555 16:48ผู้ดูแล
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.
- เสนอเป็นคำตอบโดย Stephen Toub - MSFTMicrosoft, Moderator 16 เมษายน 2555 16:48
- ทำเครื่องหมายเป็นคำตอบโดย Stephen Toub - MSFTMicrosoft, Moderator 17 เมษายน 2555 14:54
-
17 เมษายน 2555 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.
-
17 เมษายน 2555 14:52ผู้ดูแลWith 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.