Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

231 - All pipe instances are busy when connecting a pipe

3,476 views
Skip to first unread message

Bill Holt

unread,
Sep 28, 2008, 11:37:48 PM9/28/08
to
Hi,

I'm working on a pipe server & client program. The pipe server is
asynchronous and multithreaded. I used the following method to create the
server:

// code below is inside the Run() method of the server thread class
OVERLAPPED ol;
ZeroMemory(&ol, sizeof(OVERLAPPED));
HANDLE hArray[2];
hArray[0] = ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
hArray[1] = m_hStopEvent; // a global shutdown event
while(bStop==FALSE)
{
HANDLE hServerPipe = CreateNamedPipe (m_szServerName,
PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED|WRITE_DAC,PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 8192, 8192,
NMPWAIT_USE_DEFAULT_WAIT, &saPipeSecurity);
if (hServerPipe && hServerPipe != INVALID_HANDLE_VALUE)
{
BOOL bClientConnected = ConnectNamedPipe(hServerPipe, &ol);
switch (WaitForMultipleObjects(2, hArray, FALSE, INFINITE))
{
case WAIT_OBJECT_0:
if (GetOverlappedResult(hServerPipe, &ol, &dwOverlappedBytes,
TRUE))
{
// calling _beginthreadex & CloseHandle here to process
requests
}
break;
case WAIT_OBJECT_0+1:
// shut down server
bStop=TRUE;
CloseHandle(hServerPipe);
break;
}
}
}

The _beginthreadex part isn't that complicated. It passes hServerPipe as a
parameter so that the created thread can process it. The client code is as
below:

// code below is inside a client thread
// the client launches multiple threads to send requests to the server
HANDLE hPipe = CreateFile(m_szServerName, GENERIC_READ|GENERIC_WRITE,0,NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if(hPipe && hPipe != INVALID_HANDLE_VALUE)
{
OVERLAPPED ol;
ZeroMemory(&ol, sizeof(OVERLAPPED));
ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
BOOL bResult = WriteFile(hPipe,szPipeQuery,szPipeQuery.GetLength(),
&cbBytes, &ol);
if (!bResult && GetLastError() == ERROR_IO_PENDING)
bResult = GetOverlappedResult(hPipe, &ol, &cbBytes, TRUE);
while(true)
{
// here is the part to read pipe server responses
// accomplished with ReadFile and GetOverlappedResult with parsing
// abort the loop when the content is completely retrieved
// or an error is occurred
}
}


And here comes my problem. The server works for 30 requests or sometimes 200
requests. It's random. After that, the client starts to receive 231 error in
CreateFile. The actual client code handles this error and attempt 2 retries.
But from a certain point, the client will always receive 231 error when
connecting. At this point, from server trace messages, I saw that the server
has successfully processed previous requests, and waiting for new
connections. When the client receive 231, the server is actually at
WaitForMultipleObjects and hServerPipe is successfully created.

This might be because of some bug in the code I didn't post. But I found it
very difficult to debug. The server can successfully process several dozens
of requests. There is no error reported whatsoever. And all of the sudden,
the client just can't connect anymore. If I start a new instance of the
client. It'll also receive 231. Seems like the server is dead for some
reason.

How should I debug this problem? Could this be a thread synchronization
issue?

--
Best regards,
Bill Holt

Bill Holt

unread,
Sep 28, 2008, 11:47:17 PM9/28/08
to
Hi again, I also discovered that if I reduce the number of server pipe
instances from PIPE_UNLIMITED_INSTANCES to a lower value like 5. This
problem will appear very soon.

nickdu

unread,
Oct 2, 2008, 3:19:02 PM10/2/08
to
I've just been investigating a similar problem today. Similar in that I'm
getting 231 on my named pipe clients, different in that I've written the
client and server using .NET and have not yet added the overlapped stuff in
yet.

At any rate, my server would create a named pipe and wait for a connection.
After sending a couple messages to the client the communication was over and
it would disconnect the client and try connecting another client. This all
worked fine when I ran the client one at a time and the client just had this
one conversation. I then wanted to see how many conversations I could have
per second. I simply added a 1 to 100 loop in the client and once I did that
most of the requests failed. I attributed this to the client being ready to
open the file (pipe) again before the server go around to trying to
reconnect. By the way, I'm running this on my single processor laptop.

I figured I could fix this by creating two of the server threads which
create the pipe and communicate with the client. Surprisingly this didn't
fix the problem. My thought was that if the thread which was communicating
with the client was still shutting down things and had not looped around to
ConnectNamedPipe() that the other thread would have its pipe available for
the connection. Not sure why the two thread solution didn't fix the problem,
but again I'm running on a single processor laptop and multi-threaded issues
behave oddly.

After reading some posts it was suggested that I call WaitNamePipe() in the
client. I added that call if the first call to CreateFile() fails and this
seems to have resolved my problem. Code snippet:

.
.
.
pipe = Win32.File.CreateFile(pipeName,
Win32.File.GENERIC_READ | Win32.File.GENERIC_WRITE,
0, null, Win32.File.OPEN_EXISTING, 0, IntPtr.Zero);
if (pipe == Win32.File.INVALID_HANDLE_VALUE)
{
if (Marshal.GetLastWin32Error() == Win32.NamedPipe.ERROR_PIPE_BUSY)
{
if (Win32.NamedPipe.WaitNamedPipe(pipeName, 20) != 0)
{
pipe = Win32.File.CreateFile(pipeName,
Win32.File.GENERIC_READ | Win32.File.GENERIC_WRITE,
0, null, Win32.File.OPEN_EXISTING, 0, IntPtr.Zero);
}
}
}

if (pipe == Win32.File.INVALID_HANDLE_VALUE)
Console.WriteLine("Error opening pipe, result = {0}",
Marshal.GetLastWin32Error());
else
{
.
.
.
--
Thanks,
Nick

nickno...@community.nospam
remove "nospam" change community. to msn.com

Wyck

unread,
Nov 7, 2008, 1:49:02 PM11/7/08
to
"nickdu" wrote:
> [...]

> pipe = Win32.File.CreateFile(pipeName,
> Win32.File.GENERIC_READ | Win32.File.GENERIC_WRITE,
> 0, null, Win32.File.OPEN_EXISTING, 0, IntPtr.Zero);
> if (pipe == Win32.File.INVALID_HANDLE_VALUE)
> {
> if (Marshal.GetLastWin32Error() == Win32.NamedPipe.ERROR_PIPE_BUSY)
> {
> if (Win32.NamedPipe.WaitNamedPipe(pipeName, 20) != 0)
> {
> pipe = Win32.File.CreateFile(pipeName,
> Win32.File.GENERIC_READ | Win32.File.GENERIC_WRITE,
> 0, null, Win32.File.OPEN_EXISTING, 0, IntPtr.Zero);
> }
> }
> }
> [...]

Wow, I'm amazed that someone else is actually observing this. I thought I
was alone. I'm getting almost the exact same results as you guys are.

Except that in my situation I fisrt get error 231 (which is ERROR_PIPE_BUSY,
by the way) and then I call WaitNamedPipe, but WaitNamedPipe fails also, and
GetLastError returns 161 (ERROR_BAD_PATHNAME). So then I try to CreateFile
again, and get ERROR_PIPE_BUSY again, and WaitNamedPipe gives
ERROR_BAD_PATHNAME again, etc. forever. There's no amount of waiting or
re-creating the file that will solve this problem on the client end. The
only solution is to kill the server end of the pipe (by stopping the server
process and restarting it). Your single-retry after a single WaitNamedPipe
doesn't work for me.

So this makes me think that it's the fault of the implementation on the
server's side that is to blame for the problem.

Is there an explanation for this? Did you figure out why this is happening?

- Wyck

Ben Voigt [C++ MVP]

unread,
Nov 12, 2008, 6:25:14 PM11/12/08
to
Bill Holt wrote:
> Hi again, I also discovered that if I reduce the number of server pipe
> instances from PIPE_UNLIMITED_INSTANCES to a lower value like 5. This
> problem will appear very soon.

This makes me think that in some cases you forget to close the pipe on the
server side, the thread ends before you close, or some such. Use a tool
that will show you how many open handles you really have in the server, I
think oh.exe from the Windows Resource Kit and/or Process Explorer can help
here.


Alan Carre

unread,
Nov 24, 2008, 4:12:06 PM11/24/08
to
"Bill Holt" <mailbill(NOSPAM)@21cn.com.nospam> wrote in message
news:07EBF019-2108-48B0...@microsoft.com...

> Hi,
>
> I'm working on a pipe server & client program. The pipe server is
> asynchronous and multithreaded. I used the following method to create the
> server:

> // code below is inside the Run() method of the server thread class

[snip server]

> // code below is inside a client thread
> // the client launches multiple threads to send requests to the server
> HANDLE hPipe = CreateFile(m_szServerName,
> GENERIC_READ|GENERIC_WRITE,0,NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
> NULL);
> if(hPipe && hPipe != INVALID_HANDLE_VALUE)
> {
> OVERLAPPED ol;
> ZeroMemory(&ol, sizeof(OVERLAPPED));
> ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
> BOOL bResult = WriteFile(hPipe,szPipeQuery,szPipeQuery.GetLength(),
> &cbBytes, &ol);

etc...

I've actually had to debug one of these scenarios before and it was
extremely tricky to just get a feel for what's going on in the first place.
Anyway, eventually in our case (which wasn't overlapped) it boiled down to
either a blocking read or a blocking write causing either the server or
client thread to enter an infinite wait state. It looks to me here like the
server side could possibly enter an infinite (or at least non-zero-time)
wait state before each successful connection (but I doubt that's the
problem):

BOOL bClientConnected = ConnectNamedPipe(hServerPipe, &ol); <-- BLOCKING
(hServerPipe is global)
switch (WaitForMultipleObjects(2, hArray, FALSE, INFINITE)) <--
BLOCKING (hArray is global)
...

So now if a 2nd client is wanting to connect, it will have to wait for the
first client to successfully connect to, and then signal the server :

"BOOL bResult = WriteFile(hPipe,szPipeQuery,szPipeQuery.GetLength(),
&cbBytes, &ol);"

is what (hopefully) signals "ol.hEvent" on the server side [this may never
occur btw! if WriteFile returned false but *without* an IO pending error
(could be pipe busy, or too many connections or whatever)]. Well that may
happen right away, but only as long as the server is pulling data out of the
pipe to allow for more Write requests given the number of instances allowed
and their max buffer sizes. Meanwhile more clients attempt to connect and
are also waiting on the server to dequeue some data from the another client.

Well if the rate at which the server is being signaled to begin a new read
thread (ie. and then complete that particular session allowing one pipe
instance to close) is slower than the rate at which new clients are
successfully to making connections, then the number of connections (pipe
instances) will gradually rise until you reach the limit of the number of
instances allowed for that particular pipe.

My guess is you should try some debug tracing of the number of pipe
instances (from the server side) and see if that number is increasing, and
then try to determine why. Keeping in mind that the server is blocked every
time it's waiting for a new client and the last client may not have signaled
that it's time to begin reading in reasonable time, or even at all.

Hope that helps ;) Tough problems...

- Alan Carre


0 new messages