Meet you in PDC 2008 + USA Visit + Is Send() thread safe?

It is hard to believe, but three years had passed since PDC 2005… The buzzwords then where WCF, WPF, LINQ & Vista. This time it is going to be cloud services, Oslo & Windows 7. Actually the "old" stuff that was presented in 2005 still looks a bit new for most developers (myself included  :-)). It would be interesting to see how fast all the new stuff will catch up.

I will come to the USA on the 22nd of October and leave at the 6th of November, and in-between I will be available for consulting (except, of course, the PDC itself – 27-30 of October). If you are interested in a one day (or more) of review of your MSMQ solution, or MSMQ training in your site – just drop me an email to yoel@msmq.biz . If you are coming to the PDC, I will be very happy to meet you and have a chat on MSMQ, distributed solution or any other subject – again, just drop me an email.

I wouldn’t like to end this post without giving you some technical value 🙂 . Well, recently two customers asked me why MessageQueue.Send is not thread safe. Indeed, MSDN documentation states (in "MessageQueue Class" documentation):

"Only the following methods are safe for multithreaded operations: BeginPeek, BeginReceive, EndPeek, EndReceive, GetAllMessages, Peek, and Receive."

Obviously, Send is not in the list… This looks a little weird, because MQSendMessage C++ API is definitely thread safe.

This question was raised in the MSMQ newsgroup about three years ago, and I have to admit I did not fully answer it… This time, I decided to do my own little research, and wrote the following program:

class Program
{
    static MessageQueue outQueue;
    static void Main(string[] args)
    {
        outQueue = new MessageQueue(@".\private$\mtQueue");

        for (int i = 0; i < 100; i++)
        {
            Thread thr = new Thread(new ThreadStart(MyThreadProc));
            thr.Start();
        }
    }

    static void MyThreadProc()
    {
        Message msg = new Message();
        for (int i = 0; i < 100; i++)
        {
            msg.Label = string.Format("{0} : {1}", Thread.CurrentThread.ManagedThreadId, i);
            outQueue.Send(msg);
        }
    }
}

(Note that .\private$\mtQueue creation code is not included – you can create it in advance using MMC).

As you can see, the program sends 10,000 messages using 100 thread. The program runs beautifully with no failure. Does it mean that MessageQueue.Send is always thread safe? Not necessarily…

Looking at MessageQueue.InternalSend code (using Lutz Roeder’s Reflector) reveals the following code:

private void SendInternal(object obj, MessageQueueTransaction internalTransaction,
                                        MessageQueueTransactionType transactionType)
{ <Some code deleted>
              Message cachedMessage = null;
              if (obj is Message) { cachedMessage = (Message) obj; }
              if (cachedMessage == null)
              {
                           cachedMessage = this.DefaultPropertiesToSend.CachedMessage;
                           cachedMessage.Formatter = this.Formatter;
                           cachedMessage.Body = obj;
              }
   <Code for sending cachedMessage using MQSendMessage>
}

Where is the problem, then? If you are using a Message object (as I did in my code) there is no problem – it is sent "as is" and as long as you do not use the same Message object in all your threads it would work.

The problem starts when you want to use the .NET "shortcut" for serializing and sending an arbitrary .NET object in MessageQueue.Send. In this case, the .NET code will use DefaultPropertiesToSend.CachedMessage – a member variable of MessageQueue, for doing the serialization. Since this member is the same in all threads, you will get an exception when using "Send" in multiple threads.

So, I changed MyThreadProc() in the original sample as follows:

    static void MyThreadProc()
    {
        for (int i = 0; i < 100; i++)
        {
             outQueue.Send("Hello, World!");
        }
    }

Bingo! I got an exception:

Unhandled Exception: System.InvalidCastException: Specified cast is not valid.
   at System.Messaging.Interop.MessagePropertyVariants.Lock()
   at System.Messaging.Message.Lock()
   at System.Messaging.MessageQueue.SendInternal(Object obj, MessageQueueTransaction internalTransaction, MessageQueueTransactionType transactionType)
   at System.Messaging.MessageQueue.Send(Object obj)
   at TestMultithreadSend.Program.MyThreadProc() in C:\Projects\TestMultithreadSend\TestMultithreadSend\Program.cs:line 32
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, C
ontextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

To sum up – Send is actually thread safe, as long as you always send a Message object and never use send a .NET object directly. Using the Message object, BTW, is always a good idea – since it lets you add label, timeouts, recoverable option and all this stuff that make your MSMQ solution a real enterprise solution.

Close to the end of my small research I found that this issue was actually addressed recently by Microsoft – you can find more about it here .

All the best – hope to see you in PDC,

Yoel

This entry was posted in Uncategorized. Bookmark the permalink.

5 Responses to Meet you in PDC 2008 + USA Visit + Is Send() thread safe?

  1. Daniel says:

    Just wanted to say "Thanks"! It probably would have taken us a long time to figure out that our occasional null reference exceptions were the result of multi-threaded sending of serialized .Net objects. Instead I found this solution after a few mins of googling. Awesome. 🙂

  2. You completed certain nice points there. I did a search on the matter and found mainly people will consent with your blog.

  3. NirvanaRUles says:

    Nice to meet you forumers i am a new member and i would like to show to you my greate web site where you can watch anime online for free.

    There are movies and episodes of x-men and other cartoons and anime series

  4. Rajesh says:

    Do I need to implement thread safety for two applications one is sending and other one is receiving? I have following scenario:

    I have a application App1 which is sending messages to a Queue. Also, I have another application App2 which is receiving messages from the same queue. Do I need to take care of the thread safety? OR MSMQ does it automatically.

  5. kityjonelam says:

    I am glad to here the all useful inforamtion

    _________________
    mobile websites

Leave a comment