Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a good way to shutdown Threads blocked on NamedPipeServer#WaitForConnection?

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.

like image 828
Gishu Avatar asked Mar 03 '09 19:03

Gishu


2 Answers

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.


_pipeserver.Dispose(); _pipeserver = null;  using (NamedPipeClientStream npcs = new NamedPipeClientStream("pipename"))  {     npcs.Connect(100); } 
like image 200
JasonRShaver Avatar answered Oct 01 '22 09:10

JasonRShaver


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).

like image 32
Richard Avatar answered Oct 01 '22 10:10

Richard