The real problem here is "ThreadA is always in critical section". ThreadA should not be locking the critical section indefinitely.
In C#, your code for ThreadA would look something like:
Message message;
// Only lock critical section for the time it takes to modify the queue
lock(_messageQueueLock){
message = _messageQueue.Dequeue();
}
// do something with the message
In my opinion, the following general rules of thumb should be observed when using critical sections:
- Enter and exit the critical section as quickly as possible (i.e. minimize the amount of code in the critical section).
- Use critical sections to protect a resource/asset (e.g. shared memory, queue, list, etc.)
- Avoid using critical sections to protect function/method calls. If you are making function/method calls from within a critical section... you are increasing the probability of creating deadlocks.
- Avoid trying to lock a critical section from within a critical section. Failing to do so may result in potential deadlocks within your application.
- Avoid trying to access an external resource (e.g. executing a database SQL query) while in a critical section.
- Where it makes sense, I generally like to use the following naming convention for critical sections: if the asset that is being protected is called
messageQueue
... then I would name the critical sectionmessageQueueLock
Great quote from Microsoft: "When you use multithreading of any sort, you potentially expose yourself to very serious and complex bugs" [SOURCE: MSDN]