2

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?

Thanks, Nick

  • From a quick review of .NET source at https://referencesource.microsoft.com/System.Core/a.html#508a5fdc37e593b5 AnonymousPipeClientStream inherits PipeStream which inherits Stream. And Stream holds the function BeginRead. I didn't look at AnonymousPipeServerStream, but I'd imagine is implemented similarly. So, I does appear to be supported. That said there is a good way to know for sure... write up a quick sample. – Clay Ver Valen Oct 25 '16 at 22:08

2 Answers2

2

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.

Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
  • So each managed anonymous pipe instance creates their own thread to support non-blocking behavior? Wow. Certainly not the behavior I was hoping for. I just recently wrote similar pipe code on linux and it was easy to support non blocking behavior. Combining select/poll with O_NONBLOCK on the pipe instances made it quite easy. –  Oct 25 '16 at 22:30
  • Well, it is not spawning a thread per-say. It is using a thread from the threadpool to do the work of the request. – Scott Chamberlain Oct 25 '16 at 22:38
  • So that was my worry. I could be blocking a shared thread and thus cause some significant performance issues. –  Oct 25 '16 at 23:22
  • It also seems quite odd that anonymous pipes on Windows don't allow asynchronous overlapped io yet named pipes do allow it. –  Oct 25 '16 at 23:24
1

As pointed out in https://stackoverflow.com/a/51448441/14237276 Anonymous is actually built upon Named. This means one can change attributes on the handles via NamedPipe functions or if you are just looking to Read without blocking, PeekNamedPipe to get just the TotalBytesAvail before reading.

Abel
  • 437
  • 4
  • 7