8

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.

James Curran
  • 101,701
  • 37
  • 181
  • 258
  • 1
    Any reason why you're not using NamedPipeServerStream.BeginWaitForConnection() instead? – HasaniH Apr 23 '10 at 17:12
  • 1
    Basically because the thread wants to wait "forever" for a connection (unless shutdown). With Begin/End WaitForConnection, I'd have to Begin, wait a second, check for connection or timeout, and loop on timeout. – James Curran Apr 23 '10 at 17:34
  • 1
    Ok I get it. Well a slight modification to dtb's answer should give you what you need. Instead of waiting on the asyncResult, wait on a shared WaitHandle that you set from the code that awants to abort the thread. – HasaniH Apr 23 '10 at 17:40

3 Answers3

21

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
  • 213,145
  • 36
  • 401
  • 431
1

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
  • 58,241
  • 9
  • 71
  • 99
-1

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
  • 101,701
  • 37
  • 181
  • 258
  • 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 Apr 23 '10 at 18:02