The syntax for using lock
with two (or more) different objects is as follows.
lock (a) lock (b)
{
}
However, this type of usage is generally discouraged. There are a couple of reasons for this.
- The order the locks are declared must remain consistent everywhere otherwise a deadlock might occur.
- It is almost always unnecessary.
- It is a code smell.
The first reason is really a cop-out in my opinion. There are an infinite number of ways that a mistake can be made while developing. This is just one among many. And, in fact, it is actually quite easy (relative to the other kinds of mistakes that can be made) to get right. Just make sure the locks are always acquired in the same order. Plus, there is nothing inherently dangerous about using nested locks (again, as long as it is done correctly). Nested locks are acquired all the time. It is just that it is almost always done implicitly by calling into other classes or as the execution proceeds through different stack frames.
It is the second and third reasons that really matter here. Acquiring two locks in the same section of code is unnecessary because one lock is almost always sufficient. In fact, I do not think I have ever needed to acquire two locks in the same section of code; at least not explicitly. It is a code smell because it usually means you are thinking about the problem wrong. It could mean the code is convoluted or that you are using strange code paths. Structuring the code so that it only requires one lock will likely make the code much easier to follow.
On a separate note I too wonder if you are confused about the nature of how a lock works. If you are thinking that the object instance used in the lock
keyword is protected from simultaneous access then you are wrong. That is not how the lock
keyword works. The object referenced by the lock
is intended to mark a critical section of code that is guaranteed not to execute simultaneously with another (or same) section marked with the same object reference.
Update:
I took a look at your example and the first thing that jumps out at me is that this code may not be thread-safe. I cannot see the full context involved though. All I see is that this hypothetical class is using two queues internally and is pulsing two different locks. I can make some inferences, but they might be wrong. I am having a hard time envisioning a situation where you might do such a thing inside a single class. But, with that said, have you considered what happens when the thread executing this code is preempted between the locks? That is an opportunity for your class to go into a half-baked state (the item is not in either queue anymore). What happens when another thread attempts to use this class? Will it gracefully handle the situation where an item is hanging in limbo? I would have to see more code to comment further, but seeing that the arrangement of the locks allows a half-baked state to begin with is huge red flag to me.