none
Need Clarification - .Net Distibuted Transactions RRS feed

  • Question

  •  

    Hi,

     

    I need a clarification related with distributed transactions using the .Net System.Transaction namespace.  Please clarify me on the same.

     

                            The main thread in our application reads messages from a message queue and delegates the processing of each message to a thread in the ThreadPool using QueueUserWorkItem method. As part of processing  a message, a child thread (from the thread pool) needs to do some DB operations. We need a distributed transaction to coordinates the message reading and its corresponding DB operations. Since the message is read from the MSMQ by the main thread, it starts a distributed transaction for each message read from MSMQ using CommittableTransaction class. It then passes the transaction object to the child thread which processes the message. The child thread do the DB operations using the same CommittableTransaction class and commits/rollbacks it accordingly.

     

    I have written a sample program to do the above mentioned task with an exception that child thread also does MSMQ operation (Writing the message into a different queue) instead of DB operation and it is working fine. The sample code is mentioned below. Please look at this sample and let me know whether the approach is a workable solution and is a thread-safe one.
     
    namespace MyTransactions
    {
        class Program
        {
            static public void ProcessMsg(Object obj)
            {
                MessageQueue msgQueue= new MessageQueue(".\\private$\\ChildQueue");           
                msgQueue.Formatter = new BinaryMessageFormatter();
                ThreadMessage tMsg = (ThreadMessage)obj;
                Transaction.Current = tMsg.tx;
                msgQueue.Send(tMsg.msg, MessageQueueTransactionType.Automatic);
                Console.WriteLine("Thread message {0} ", tMsg.msg);
                tMsg.tx.Commit();           
            }
            class ThreadMessage
            {
                public CommittableTransaction tx;
                public string msg;
                public ThreadMessage(CommittableTransaction tx, string msg)
                {
                    this.tx = tx;
                    this.msg = msg;
                }
            }
            static void Main(string[] args)
            {          
                int i = 1;
                while (i < 4)
                {
                    MessageQueue msgQueue= new MessageQueue(".\\ParentQueue");
                    msgQueue.Formatter = new BinaryMessageFormatter();
                    CommittableTransaction tx = new CommittableTransaction();              
                    Transaction.Current = tx;               
                    string msg = msgQueue.Receive(MessageQueueTransactionType.Automatic).Body.ToString();
                    ThreadPool.QueueUserWorkItem(ProcessMsg, new ThreadMessage(tx, msg));               
                    i++;
                }
                Console.ReadLine();           

            }
        }
    }

    In MSDN, it is mentioned as below:

                             The CommittableTransaction class provides an explicit way for applications to use a transaction, as opposed to using the TransactionScope class implicitly. Unlike the TransactionScope class, the application writer needs to specifically call the Commit and Rollback methods in order to commit or abort the transaction. However, only the creator of a transaction can commit the transaction. Therefore, copies of a committable transaction, obtained through the Clone method are not committable.


    I am getting confusion with the red-highlighted sentence that only the creator of a transaction can commit the transaction. I am not getting the exact meaning of the creator (is it the thread which creates the CommittableTransaction object or the original CommitableTransaction object itself). Please clarify me on this.

     

    Thank you.

     

    Regards,

    Ilayaraja M

    Thursday, June 5, 2008 10:23 AM

Answers

  • The comment in red does not refer to threading, just where the CommittableTransaction object reference came from.  You're good on that.

    Some oddities in your code, like creating the parent queue inside the loop.  The Transaction.Current assignment is a problem, especially in the Main() function.  I doubt you need it there.  Anyhoo, you'd probably need a lock around Current and Commit().

    Hans Passant.
    • Marked as answer by Bruno Yu Wednesday, June 11, 2008 3:53 AM
    Thursday, June 5, 2008 11:44 AM
    Moderator
  • Run this Google query and study the content of the links found.  You'll step in deep doggie-doo if you don't know what can go wrong when you use threads.  I'm fairly sure that in this particular case, you should *not* use threads.
    Hans Passant.
    • Marked as answer by Bruno Yu Wednesday, June 11, 2008 3:53 AM
    • Unmarked as answer by IlayarajaMano Thursday, June 12, 2008 2:00 PM
    • Marked as answer by IlayarajaMano Thursday, June 12, 2008 2:01 PM
    • Unmarked as answer by IlayarajaMano Thursday, June 12, 2008 2:01 PM
    • Marked as answer by IlayarajaMano Thursday, June 12, 2008 2:01 PM
    Saturday, June 7, 2008 9:54 AM
    Moderator

All replies

  • The comment in red does not refer to threading, just where the CommittableTransaction object reference came from.  You're good on that.

    Some oddities in your code, like creating the parent queue inside the loop.  The Transaction.Current assignment is a problem, especially in the Main() function.  I doubt you need it there.  Anyhoo, you'd probably need a lock around Current and Commit().

    Hans Passant.
    • Marked as answer by Bruno Yu Wednesday, June 11, 2008 3:53 AM
    Thursday, June 5, 2008 11:44 AM
    Moderator
  • Hi Hana Passant,

          Thanks for your kind reply. I aggree that I can move the parent queue creaion outside the loop. But, I am not getting what the problem is with Transaction.current assigenment and why a lock is needed around Current and Commit. (Actually, I need to set the Transaction.Current in a entry point of one of my threads not in the main method). Please enlighten me on it.

    Thanks and regards,
    Ilayaraja M

     
    Saturday, June 7, 2008 7:46 AM
  • Run this Google query and study the content of the links found.  You'll step in deep doggie-doo if you don't know what can go wrong when you use threads.  I'm fairly sure that in this particular case, you should *not* use threads.
    Hans Passant.
    • Marked as answer by Bruno Yu Wednesday, June 11, 2008 3:53 AM
    • Unmarked as answer by IlayarajaMano Thursday, June 12, 2008 2:00 PM
    • Marked as answer by IlayarajaMano Thursday, June 12, 2008 2:01 PM
    • Unmarked as answer by IlayarajaMano Thursday, June 12, 2008 2:01 PM
    • Marked as answer by IlayarajaMano Thursday, June 12, 2008 2:01 PM
    Saturday, June 7, 2008 9:54 AM
    Moderator
  • Hi Hana Passant,

         I know the issues of race conditions and deadlocks. But I am not getting how a currency issue does happen while assigning the Transaction.Current property and the Commit method call. 

        Since Transaction.Current is a thread static variable, I don't think there is any concurrency problem in assigning it in the ProcessMsg method- (considering the fact that the method runs under the context of a new thread every time it is invoked and each thread will have a separate copy of the Transaction.Current object). Even in case of Main method, it always runs in the main thread and I am just changing the value of the Transaction.Current propery (of the main thread). So I consider it as thread-safe operation. In addition, the reason why I have put the Transction.Current assignment in the Main method is that the subsequent msgQueue.Receive method uses the ambient transaction to read a message from the parent queue.  Actually, my aim is to use a same transaction while reading a message in  the main thread as well as processing it in the child thread. That is why I am passing the transaction object to the child thread.

    I also thinks that the commit method call on the transaction object in the ProcessMsg method is also thread safe (any transaction object created in the Main method is shared by only two threads; one is the main thread, which creates and reads the message from a queue using the transaction object, and the other one is the child thread which processes the message. By the time the Commit method is called in the child thread, the main thread has finished off its work with the transaction object. So no more than one thread currently using the transaction object and there won't be any currency issue with the method call).

    Please let me know if I am wrong in my comments above anywhere.


    Thanks and regards,
    Ilayaraja M


    Wednesday, June 11, 2008 10:44 AM
  • Hi Hana Passant,

       Can you please cofirm me whether the details that I mentioned in my previous reply are correct?

    Thanks and regards,
    Ilayaraja M
    Sunday, June 15, 2008 5:33 PM
  • I don't see it documented as such in the MSDN library.  But there is an internal class named System.Transactions.ContextData that has a [ThreadStatic] member.  It is involved with Transaction.Current, it seems therefore likely that the property is thread safe.  It would certainly be the Right Thing to do.  I'd gamble on it being safe, but do verify.
    Hans Passant.
    Sunday, June 15, 2008 6:46 PM
    Moderator
  • Hi Hana Passant,

      Thanks for giving the information.

      In fact, in the MSDN documentation for framework 3.5 (http://msdn.microsoft.com/en-us/library/system.transactions.transaction.current.aspx) , the following remark is given for the Transaction.Current property:

    For more information on ambient transactions, please see the "Transaction Flow Management" section of the Implementing an Implicit Transaction using Transaction Scope topic.

    Although you can set the ambient transaction using this property, you should use the TransactionScope object to manipulate the ambient transaction whenever possible.

    This property is thread static.

    (Note: It is not mentioned in the documentation for .Net 2.0 framework.)

    So I think the method as well as my code block is thread-safe. Please let me know if there are any other issues with the code block.

    Thanks again for your kind help.

    Regards,
    Ilayaraja M

    • Edited by IlayarajaMano Monday, June 16, 2008 8:18 AM Added link
    Monday, June 16, 2008 8:14 AM