Thursday, May 03, 2012

Help! How Do I Detect When a Client Thread Exits?

Here’s an interesting library writer’s dilemma. In my library (in my case EasyNetQ) I’m assigning thread local resources. So when a client creates a new thread and then calls certain methods on my library new resources get created. In the case of EasyNetQ a new channel to the RabbitMQ server is created when the client calls ‘Publish’ on a new thread. I want to be able to detect when the client thread exits so that I can clean up the resources (channels).

The only way of doing this I’ve come up with is to create a new ‘watcher’ thread that simply blocks on a Join call to the client thread. Here a simple demonstration:

First my ‘library’. It grabs the client thread and then creates a new thread which blocks on ‘Join’:

public class Library
{
public void StartSomething()
{
Console.WriteLine("Library says: StartSomething called");

var clientThread = Thread.CurrentThread;
var exitMonitorThread = new Thread(() =>
{
clientThread.Join();
Console.WriteLine("Libaray says: Client thread existed");
});

exitMonitorThread.Start();
}
}

Here’s a client that uses my library. It creates a new thread and then calls my library’s StartSomething method:

public class Client
{
private readonly Library library;

public Client(Library library)
{
this.library = library;
}

public void DoWorkInAThread()
{
var thread = new Thread(() =>
{
library.StartSomething();
Thread.Sleep(10);
Console.WriteLine("Client thread says: I'm done");
});
thread.Start();
}
}

When I run the client like this:

var client = new Client(new Library());

client.DoWorkInAThread();

// give the client thread time to complete
Thread.Sleep(100);

I get this output:

Library says: StartSomething called
Client thread says: I'm done
Libaray says: Client thread existed

The thing is, I really don’t like the idea of all these blocked watcher threads hanging around. Is there a better way of doing this?

7 comments:

Karl Nilsson said...

Thought: If a threadlocal resource implements IDisposable would Dispose() be called when the thread finishes?

Mike Hadlow said...

Hi Karl, No, it wouldn't. Something has to call Dispose.

Mike Hadlow said...

I've copied this onto StackOverflow where there's quite a good discussion going on: http://stackoverflow.com/questions/10432494/how-do-i-detect-when-a-client-thread-exits

Karl Nilsson said...

Good point.

Omer Mor said...

I answered your questing over at stackoverflow: http://stackoverflow.com/a/10435718/61061

In short, the combination of thread-static resource that has a finalizer can be used to observe the death of threads.

I hope it helps. I think it's more elegant than your extra waiting thread.

Karl Nilsson said...

:) Just came back to suggest adding a destructor but Omer beat me to it. Too slow...

Anonymous said...

What in the world are you doing putting an item like that on thread local storage?