views:

281

answers:

2

I have a windows service that has a lot of work to do simultaneously. I've looked into threading and found the ThreadPool class. I'm currently stuck, it doesn't seem to have any effect, it's like whatever I'm queuing is never run or called. In the service's OnStart() event I create a thread like this:

Thread mainThread = new Thread(ReceiveMessages);
mainThread.Start();

Inside the method ReceiveMessages() I have a routine that checks a message queue and then iterates through the messages. For each iteration I call the following code to do some work with each message:

ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state)
{
    Interpreter.InsertMessage(encoding.GetBytes(MessageBody));
}), null);

I think the syntax is right, it compiles with no issues, but I can't help but feel that I am missing something. When I run the service, nothing happens. However, if I replace the above code snippet with this:

insertThread = new Thread(delegate() { Interpreter.InsertMessage(encoding.GetBytes(MessageBody)); });
insertThread .Start();

It works 100%. It's not very efficient though and can cause the service to crash (which is does occasionally, the reason why I'm trying to use TheadPool instead). Can anyone shed some light on the subject?

+1  A: 

By default, when you create a new Thread, the thread is a Foreground thread. ThreadPool threads, however, have IsBackground set to true.

This means that a threadpool thread will not keep your application alive. This is probably why it's never "running" - it's just shutting down right away.

It's not very efficient though and can cause the service to crash (which is does occasionally, the reason why I'm trying to use TheadPool instead). Can anyone shed some light on the subject?

The self-constructed thread should be just as efficient (once the thread is up and running). The "crashing" will not be helped in any way by the ThreadPool thread - you'll still need to debug your service appropriately.

Reed Copsey
I understand what you're saying. ReceiveMessages() has a while(true) loop that continually checks the message queue though, so every time there are messages, each message gets it's own thread to do some work. Perhaps that has some sort of effect?
Mr. Smith
@Mr. Smith: If the main thread terminates, you'll shut down the applciation (if you're using ThreadPool threads), since you need to have at least one non-background thread to keep it alive...
Reed Copsey
Yes, but isn't that what I'm doing in the OnStart() event? You said that creating a new Thread is by default a Foreground thread, wouldn't that make mainThread in my first code snippet above a thread that would keep it alive? I only utilize the ThreadPool inside that thread. What do you think?
Mr. Smith
+2  A: 

It looks like you're creating a closure over MessageBody in your wait callback. If the caller's MessageBody property is null by the time the thread pool executes the work item, then that's what InsertMessage will operate on.

You need to define an overload of Interpreter.InsertMessage that accepts an object and use that as your WaitCallback:

public void InsertMessage(object messageBody) {
    this.InsertMessage((byte[])messageBody);
}

Then pass the message body bytes as the second parameter:

ThreadPool.QueueUserWorkItem(new WaitCallback(Interpreter.InsertMessage), 
                             encoding.GetBytes(MessageBody));
Jeff Sternal
That is perfect! Works like a charm!
Mr. Smith