views:

3044

answers:

5

To simplify, this is a situation where a NamedPipe SERVER is waiting for a NamedPipe CLIENT to write to the pipe (using WriteFile())

The Windows API that is blocking is ReadFile()

The Server has created the synchronous pipe (no overlapped I/O) with blocking enabled

The client has connected, and now the server is waiting for some data.

In the normal flow of things, the client sends some data and the server processes it and then returns to ReadFile() to wait for the next chunk of data.

Meanwhile an event occurs (user input for example) and the NamedPipe SERVER must now execute some other code, which it cannot do while the ReadFile() is blocking.

At this point I need to mention that the NamedPipe Client is not my application, so I have no control over it. I cannot make it send a few bytes to unblock the server. It is just going to sit there and send no data. Since I do not have control of the Client implementation I cannot change anything on that end.

One solution would be to create a separate thread in which all ReadFile() operations are performed. That way when the event occurs, I can just process the code. The problem with that, is that the event also requires a separate thread, so now I have two additional threads for each instance of this server. Since this needs to be scalable, this is undesirable.

From another thread I have tried calling

 DisconnectNamedPipe()

and

 CloseHandle()

they both will not return (until the client writes to the pipe.)

I cannot connect to the same pipe and write a few bytes because:

"All instances of a named pipe share the same pipe name, but each instance has its own buffers and handles, and provides a separate conduit for client/server communication."

http://msdn.microsoft.com/en-us/library/aa365590.aspx

I need a way to fake it out, So the $64k dollar question is:

How can I break the blocking of ReadFile()?

A: 

The problem with that, is that the event also requires a separate thread, so now I have two additional threads for each instance of this server. Since this needs to be scalable, this is undesirable.

Never in my career have I found that "more threads" == "less scalable". How many of these "server" instances do you have?

Normally, an operation needs to be performed in a separate thread if that operation is going to block and the system needs to be responsive while the operation is blocked.

Kevin
How many of these "server" instances do you have?They are talking about up to 10k... I know the overhead is low, but the idea is to minimize this.I am just asking the question... is it possible?
Mike Trader
I don't think you can have 10k threads :-)
alex2k8
Yes that would require a thread pool, but the point is there is a performance overhead associated with starting a new thread, and each thread is also allocated some memory for its stack etc. This adds up and is undesirable.
Mike Trader
At first, you are not required to kill a pool thread. Just let it sleep until it needed next time. Take a look on this article http://msdn.microsoft.com/en-us/library/system.threading.threadpool.aspx (this is for .Net, but you can borrow ideas)
alex2k8
+1  A: 

Mike,

You can't cancel synchronous ReadFile. But you can switch to asynchronous (overlapped) operations. By doing this, you can implement a pretty scalable architecture.

Possible algorithm (just an idea):

  • For each new client call ReadFile
  • WaitForMultipleObjects where the handles are overlapped.hEvent + your custom events
  • Iterate over signalled events, and schedule them for execution by threads from a threads pool.

This way you can have only few threads to receive connections and read data, while the actual data processing can be done by the threads pool.

alex2k8
Yes. That is the next stage of the design. unfortunatly I inherited most of this problem. The IPC is not open to me, nor is the FastCGI spec. I was a long shot, but I thoughtI would ask in case someone had a technique for breaking the block.
Mike Trader
+1  A: 

Take a look on CancelSynchronousIo

Marks pending synchronous I/O operations that are issued by the specified thread as canceled.

And CancelIo/CancelIoEx:

To cancel all pending asynchronous I/O operations, use either:

CancelIo — this function only cancels operations issued by the calling thread for the specified file handle.

CancelIoEx — this function cancels all operations issued by the threads for the specified file handle.

alex2k8
Oooh. I missed that...Minimum supported client Windows VistaMinimum supported server Windows Server 2008Unfortunatly this is Windows Server 2003.Darn
Mike Trader
Google for 'msdn Synchronous and Asynchronous I/O' article. Seems the only option left is TerminateThread, but this would be a bad idea (google for 'msdn TerminateThread can result in the following problems')
alex2k8
More info here: http://msdn.microsoft.com/en-us/library/aa480216.aspx ("Win32 I/O Cancellation Support in Windows Vista").
dangph
A: 

Asynchronous I/O operations do not have to block any thread if they use I/O Completion Ports. See: http://msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx

+1  A: 

Try this before ReadFile :

BOOL WINAPI PeekNamedPipe( __in HANDLE hNamedPipe, __out_opt LPVOID lpBuffer, __in DWORD nBufferSize, __out_opt LPDWORD lpBytesRead, __out_opt LPDWORD lpTotalBytesAvail, __out_opt LPDWORD lpBytesLeftThisMessage );

if(TotalBytesAvail > 0) ReadFile(....);

-AV-

This works as advertised, but assumes that there is data in the pipe to be read. The problem is that we need ReadFile() to block UNTIL there is data sent. Then we read the data and return to the blocking status of ReadFile(). If we do not use the blocking of ReadFile(0 then we would need to constantly check the pipe (defeating the purpose of the blocking in the first place)
Mike Trader