nickdu nickdu - 9 months ago 102
C# Question

non-blocking io on Windows anonymous pipes

I'm looking to do non-blocking io on Windows anonymous pipes. This is a .NET project so I plan on using managed classes if possible. I see that .NET does have an AnonymousPipeServerStream and an AnonymousPipeClientStream. I see both BeginRead()/BeginWrite() and ReadAsync()/WriteAsync() methods. However from:

Anonymous Pipe Operations

it says:

"Asynchronous (overlapped) read and write operations are not supported by anonymous pipes. This means that you cannot use the ReadFileEx and WriteFileEx functions with anonymous pipes. In addition, the lpOverlapped parameter of ReadFile and WriteFile is ignored when these functions are used with anonymous pipes."

So I'm wondering how the managed asynchronous methods work? Are they implemented as synchronous methods which are run on an io worker thread? If so, wouldn't that be a problem if I end up blocking several io worker threads?


Answer Source

First of all, the default implementation of ReadAsync()/WriteAsync() just call the BeginRead()/BeginWrite() methods using a trimmed version of TaskFactory<Int32>.FromAsync, and neither PipeStream nor AnonymousPipeServerStream override it so we only need to know how BeginRead()/BeginWrite() works.

In the constructor for AnonymousPipeServerStream it calls

InitializeHandle(serverSafePipeHandle, true, false);

The last parameter of InitializeHandle is isAsync which if it is false calling BeginRead() will call

return base.BeginRead(buffer, offset, count, callback, state);

the base implementation of BeginRead( creates a new thread and calls the synchronous _stream.Read( method.

So the answer to your question is how do they get async to work is "They don't, they just fake it by calling the synchronous method on another thread."

P.S.: If you do a File.Open("SomeFile") it will do the same thing. You must use FileStream and explicitly pass in FileOptions.Asynchronous to get the Begin methods and the Async methods to not fake it by spawning a new thread to do the request.