.NET Framework Bookmark and Share   
 index > Common Language Runtime > Need Clarification - .Net Distibuted Transactions
 

Need Clarification - .Net Distibuted Transactions

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

IlayarajaMano
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.
nobugz
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.
nobugz
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.
nobugz
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 ofone of my threads not in the main method). Please enlighten me on it.

Thanks and regards,
Ilayaraja M

IlayarajaMano
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.
nobugz

Hi Hana Passant,

I know the issues of race conditions anddeadlocks. But I am not getting howa 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 concurrencyproblem in assigning it in the ProcessMsg method- (considering the fact thatthe 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, italways 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 haveput the Transction.Current assignment in theMain method is that the subsequent msgQueue.Receive method uses the ambient transaction to reada message fromthe parent queue.Actually, my aim is tousea same transactionwhile reading a messagein 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 thechild thread whichprocesses the message. By the time the Commit method is called in the child thread, the main threadhas 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


IlayarajaMano
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
IlayarajaMano
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.
nobugz
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 mentionedin the documentation for .Net 2.0 framework.)

So I thinkthe method as well as my code blockis 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

IlayarajaMano

You can use google to search for other answers

Custom Search

More Threads

• Exception trace is not available when program crashes
• System.Security.Cryptography.ProtectedData - Unable to reference this class.
• Design Windows Service not to allow the sysem shutdown
• .NET Framework 2.0, Problem while sending Fax.
• Exception HRSULT:0x8007007E
• Safe handle has been closed.
• ToInt32 Exception
• Knowing when an AppDomain is unloaded
• How to get StackOverflowException stacktrace without debugger?
• APM vs. Threading