MSMQ, MessageQueue.Receive, and Thread.Abort
Using MSMQ in a .NET app is incredibly easy – the framework does most of the grunt work for you. Something that seems fairly natural is to use MSMQ in a Service.
Services are controlled by the Service Control Manager. When you say “net start myservice”, assuming MyService is installed with the SCM, your service is invoked, and is expected to contact the SCM and wait for commands. This is handled by the framework so that all you have to do is implement OnStart and OnStop.
Typically OnStart starts a thread, and OnStop signals the thread to stop. An easy way to signal the thread to stop is to call Thread.Abort on the thread – this raises a ThreadAbortException, which is an exception that can’t be suppressed – you can catch it, but when your catch scope ends, the CLR just throws it again, all the way out until your thread exits.
This is somewhat dangerous obviously (since you can get interrupted anywhere), but if your exception handling is robust then you should be fine, and it’s very easy to implement.
The bummer is that if the purpose of your thread is to receive messages from a MessageQueue and process them, then you’re probably blocking in MessageQueue.Receive. This is not a .NET function, and Thread.Abort has no effect on it.
You could call MessageQueue.Receive with a timeout, but instead of simply returning failure, the runtime actually throws an exception when the timeout expires – meaning you’d be constantly throwing exceptions as part of your normal operation, something to avoid.
So here’s what you do
IAsyncResult result = queue.BeginReceive();
result.AsyncWaitHandle.WaitOne();
return queue.EndReceive(result);
Now instead of blocking inside the MessageQueue.Receive function, you’re blocking in WaitOne, which will be woken up by the Thread.Abort.
April 16th, 2007 at 1:50 pm
Thanks Steve for the insight. I had no clue that Receive() is not a .net function. Is it a COM function?
Anyways this has prevented me furthur pain.
sujeet
June 10th, 2008 at 3:32 pm
Thanks, this is exactly the answer i was looking for. I had the timeout approach in mind, but knew it was not an elegant solution.
April 24th, 2010 at 3:33 pm
Thanks Steve, perfect answer for the problem I was experiencing..