views:

1779

answers:

5

I start my application which spawns a number of Threads, each of which creates a NamedPipeServer (.net 3.5 added managed types for Named Pipe IPC) and waits for clients to connect (Blocks). The code functions as intended.

private void StartNamedPipeServer()
  {
    using (NamedPipeServerStream pipeStream =
                    new NamedPipeServerStream(m_sPipeName, PipeDirection.InOut, m_iMaxInstancesToCreate, PipeTransmissionMode.Message, PipeOptions.None))
    {
      m_pipeServers.Add(pipeStream);
      while (!m_bShutdownRequested)
      {
        pipeStream.WaitForConnection();
        Console.WriteLine("Client connection received by {0}", Thread.CurrentThread.Name);
        ....

Now I also need a Shutdown method to bring this process down cleanly. I tried the usual bool flag isShutdownRequested trick. But the pipestream stays blocked on the WaitForConnection() call and the thread doesn't die.

public void Stop()
{
   m_bShutdownRequested = true;
   for (int i = 0; i < m_iMaxInstancesToCreate; i++)
   {
     Thread t = m_serverThreads[i];
     NamedPipeServerStream pipeStream = m_pipeServers[i];
     if (pipeStream != null)
     {
       if (pipeStream.IsConnected)
          pipeStream.Disconnect();
       pipeStream.Close();
       pipeStream.Dispose();
     }

     Console.Write("Shutting down {0} ...", t.Name);
     t.Join();
     Console.WriteLine(" done!");
   }
}

Join never returns.

An option that I didnt try but would possibly work is to call Thread.Abort and eat up the exception. But it doesn't feel right.. Any suggestions

Update 2009-12-22
Sorry for not posting this earlier.. This is what I received as a response from Kim Hamilton (BCL team)

The "right" way to do an interruptible WaitForConnection is to call BeginWaitForConnection, handle the new connection in the callback, and close the pipe stream to stop waiting for connections. If the pipe is closed, EndWaitForConnection will throw ObjectDisposedException which the callback thread can catch, clean up any loose ends, and exit cleanly.

We realize this must be a common question, so someone on my team is planning to blog about this soon.

A: 

You must Close() the pipe, it will interrupt all blocking operations associated with the pipe.

If you don't have a reference to the pipe, you'll have to redesign your app for signaling that you want to Close() that pipe.

John Leidegren
Doesn't work. Disconnect(), Close() and Dispose() all execute successfully but the WaitForConnection call is not unblocked. I've updated question with code for the Stop() method.
Gishu
It should, I have some trouble understanding your program, posting all the code isn't really gonna help with that. But you need to manually close all the pipes. Are you sure you aren't blocked by those Join() calls? The .NET runtime will remain active until all non-background threads exit.
John Leidegren
For all I know you could be waiting for the current thread to exit, I think you're misusing those Join() calls. They block the calling thread, how are you spawning your threads?
John Leidegren
Thread aNewThread = new Thread(new ThreadStart(StartNamedPipeServer)); followed by aNewThread.Start() - I've got thru to someone on the MS team.. will post back with answers/solutions/workarounds..
Gishu
How do you prevent the entry thread (Main thread) from exiting?
John Leidegren
+3  A: 

Switch to the asynchronous version: BeginWaitForConnection.

If it does ever complete, you'll need a flag so the completion handler can just call EndWaitForConnection absorbing any exceptions and exiting (call End... to ensure any resources are able to be cleaned up).

Richard
A: 

One way that could work is checking for m_bShutdownRequested right after the WaitForConnection.

During the shutdown process set the bool. After that send dummy messages to all the existing pipes so they open the connection and check the bool and shut down cleanly.

Sam Saffron
+3  A: 

This is cheesy, but it is the only method I have gotten to work. Create a 'fake' client and connect to your named pipe to move past the WaitForConnection. Works every time.

Also, even Thread.Abort() did not fix this issue for me.

JasonRShaver
A: 

I have the same problem. Who wrote this API?

jkg0
we all make some non-optimal choices:) see update in the question for a resolution.
Gishu