views:

228

answers:

4

I have a managed thread which is waiting, blocked, in an unmanaged code (specifically, it on a call to NamedPipeServerStream.WaitForConnection() which ultimitely calls into unmanaged code, and does not offer a timeout).

I want to shut the thread down neatly.

Thread.Abort() has no effect until the code returns to the managed realm, which it won't do until a client makes a connection, which we can't wait for).

I need a way "shock" it out of the unmanaged code; or a way to just kill the thread even while it's in unmanaged land.

A: 

I think you may want to look here. It talks about thread abort, and potential alternatives.

http://stackoverflow.com/questions/2251964/c-thread-termination-and-thread-abort

Kevin
+6  A: 

Have you tried using the non-blocking NamedPipeServerStream.BeginWaitForConnection method?

using (NamedPipeServerStream stream = ...)
{
    var asyncResult = stream.BeginWaitForConnection(null, null);

    if (asyncResult.AsyncWaitHandle.WaitOne(5000))
    {
        stream.EndWaitForConnection(asyncResult);
        // success
    }
}

You don't necessarily have to use a fixed timeout. You can use a ManualResetEvent to signal when the thread should stop waiting for the connection:

ManualResetEvent signal = new ManualResetEvent(false);

using (NamedPipeServerStream stream = ...)
{
    var asyncResult = stream.BeginWaitForConnection(_ => signal.Set(), null);

    signal.WaitOne();
    if (asyncResult.IsCompleted)
    {
        stream.EndWaitForConnection(asyncResult);
        // success
    }
}

// in other thread
void cancel_Click(object sender, EventArgs e)
{
    signal.Set();
}
dtb
The signal also needs to be set inside a callback passed to BeginWaitForConnection. Then the example will be complete.
Jeffrey L Whitledge
+1  A: 

There is no way to "neatly" shut down a thread from the outside, if that thread is running unmannaged code. There are a couple of ways to abruptly Terminate the thread, but that's probably not what you want.

You should use BeginWaitForConnection instead.

Jeffrey L Whitledge
A: 

Actually, the solution I used (which occurred to me as I was writing up the question), was to, after aborting all the threads, just to create (and immediately dispose) a client for each thread.

  threads.ForEach(thread=> thread.Abort());
  threads.ForEach(thread=>
              {
                   var client = new PipeClient(ServiceName); 
                   client.Connect(); 
                   client.Dispose();
              });

With the connection, it returns to managed code, and the Abort() kicks in (the thread catches ThreadAbortException and cleans itself up)

This doesn't work for the general case (i.e., the question posed in the title), but it works for me...

James Curran
If you go with this crazy scheme, be sure to use an appropriate timeout on Connect, just in case another process establishes a connection at just the wrong moment, causing the listening thread to abort and this thread to block!
Jeffrey L Whitledge