As I mentioned in my previous post, I have a need to consistently pass an operation context to any thread I choose to spin. Doing so manually, as I did here, involves a lot of ugly, repetitive code for every thread. A lot of room for mistakes and bugs.
So using the power that .NET delegates give us, I’ve built a generic Context-bound threadpool queue class to wrap this logic for me.
This class has two methods – the first (executing on the originator thread) wraps the call to ThreadPool.QueueUserWorkItem, passing it my operation context and details on what to execute on the new thread. The second is launched on the new thread, sets its own context to the parameter and invokes the requested method.
Using delegates and the params statement, we can have this work for any delegate taking any number of arguments. Naturally, since this executes on a different thread, there’s no point in having the delegate have a return value.
public void QueueDelegate(Delegate function, params object parameters)
param.Context = OperationContext.Current;
param.Function = function;
param.Parameters = parameters;
private void Launcher (object state)
ParameterStruct param = (ParameterStruct)state;
OperationContext.Current = param.Context;
Notes and warning:
- To allow any number of arguments to pass through, my method takes a params object argument. This means that calling our delegate through the context-bound threadqueue is inherently NOT typesafe. There are no checks made to ensure the given parameters match the delegate. This can be added manually using reflection, but I decided to leave it out.
- This class will spin threads from the threadpool. It can be easily adapted to start custom threads using Thread.Start(), and this can even be passed as a parameter. I’ll leave it as an exercise for whomever feels like doing it.
- This code was written to pass WCF’s OperationContext object to a new thread. It can be used to transfer anything else with very little modification. With a bit of work, you can write it so it can transfer anything you tell it to.
Using this class is as easy as calling the ThreadPool methods. The main difference is that instead of having a method that matches the WaitCallback delegate, we can pass in any delegate we want
public delegate void MyCustomDelegate(int param1, string param2);
public void MyCustomMethod (int param1, string param2)
// Do work;
ContextThreadQueuer.QueueDelegate(new MyCustomDelegate(MyCustomMethod, 5, “whoo!”);
Note that because we use the base System.Delegate object as a parameter, we have to implicitly call “new MyCustomDelegate()” and can’t have the compiler automatically infer the delegate type.