How to use Multiple Variables for a lock Scope in C#
Asked Answered
C

3

10

I have a situation where a block of code should be executed only if two locker objects are free.

I was hoping there would be something like:

lock(a,b)
{
    // this scope is in critical region
} 

However, there seems to be nothing like that. So does it mean the only way for doing this is:

lock(a)
{
    lock(b)
    {
        // this scope is in critical region
    }
}

Will this even work as expected? Although the code compiles, but I am not sure whether it would achieve what I am expecting it to.

Coletta answered 20/5, 2010 at 13:17 Comment(3)
Couldn't this cause lock problems? say an object locks a, and another locks b, now you would have a deadlock where object1 blocks a waiting for b and object2 blocks b waiting for a. I'm not that familiar with locks, but this just seems bad.Decorticate
That's why locking order is important, as all the answers so far have mentioned. Sometimes you need to have multiple locks, and in those cases one of the standard patterns to use is to enforce (through convention at least) an ordering on the locks. For instance, you'd say any time you want to get the lock on b you must first get the lock on a. Causes more contention, but prevents deadlocks. It's always better to avoid this kind of thing when possible, but sometimes it's necessary.Fronton
@Tester101: Yes I am aware that if not properly handled, it will cause deadlock.Coletta
C
5

I'd expect it to, though there'd be a case where it could potentially cause a deadlock condition.

Normally, the code will attempt to lock a and then proceed to lock b if that succeeded. This means that it would only execute the code if it could lock both a and b. Which is what you want.

However, if some other code has already got a lock on b then this code will not do what you expect. You'd also need to ensure that everywhere you needed to lock on both a and b you attempt to get the locks in the same order. If you get b first and then a you would cause a deadlock.

Crew answered 20/5, 2010 at 13:21 Comment(6)
Actually it will not fail if something else has a lock on b - it will wait until that is released.Saint
@TomTom: If the other thread just tries to access one of the locks, then we won't have any problem, but if it tries to lock both a and b and in reverse order, there is good chance for deadlock. @ChrisF: Are they outer curly braces necessary in your edit, or you did this just to make code look cleaner?Coletta
@Gunner - just an attempt to make the code look cleaner and clarify the scope of the lock. Hope that's OK.Crew
@ChrisF: Ah it's ok. I guess these lock scopes work just like other scoping contexts. For example, in many cases of nested for loop, we usually don't place curly braces for the outer loop.Coletta
@Gunner - yes, ultimately just a matter of coding style, but I feel it adds a little bit of clarity when viewing code outside an IDE where you don't have the tools to help you.Crew
Just adding my two cents (only a year later), this ordering problem everyone is dancing around is called the Dining Philosophers Problem: en.wikipedia.org/wiki/Dining_philosophers_problemProudfoot
F
18
lock(a) lock(b) { // this scope is in critical region }

This could would block until the thread can acquire the lock for a. Then, with that lock acquired, it would block until the thread can acquire the lock for b. So this works as expected.

However, you have to be careful not to do this somewhere else:

lock(b) lock(a) { // this scope is in critical region }

This could lead to a deadlock situation in which thread 1 has acquired the lock for a and is waiting to acquire the lock for b, and thread 2 has acquired the lock for b and is waiting to acquire the lock for a.

Fireguard answered 20/5, 2010 at 13:22 Comment(0)
F
11

Requesting the lock on both should work fine. lock(a) will block until a is free. Once you have that lock, lock(b) will block until you have b. After that you have both.

One thing you need to be very careful about here is the order. If you're going to do this make sure you always get the lock on a before getting the lock on b. Otherwise you could very easily find yourself in a deadlock situation.

Fronton answered 20/5, 2010 at 13:20 Comment(0)
C
5

I'd expect it to, though there'd be a case where it could potentially cause a deadlock condition.

Normally, the code will attempt to lock a and then proceed to lock b if that succeeded. This means that it would only execute the code if it could lock both a and b. Which is what you want.

However, if some other code has already got a lock on b then this code will not do what you expect. You'd also need to ensure that everywhere you needed to lock on both a and b you attempt to get the locks in the same order. If you get b first and then a you would cause a deadlock.

Crew answered 20/5, 2010 at 13:21 Comment(6)
Actually it will not fail if something else has a lock on b - it will wait until that is released.Saint
@TomTom: If the other thread just tries to access one of the locks, then we won't have any problem, but if it tries to lock both a and b and in reverse order, there is good chance for deadlock. @ChrisF: Are they outer curly braces necessary in your edit, or you did this just to make code look cleaner?Coletta
@Gunner - just an attempt to make the code look cleaner and clarify the scope of the lock. Hope that's OK.Crew
@ChrisF: Ah it's ok. I guess these lock scopes work just like other scoping contexts. For example, in many cases of nested for loop, we usually don't place curly braces for the outer loop.Coletta
@Gunner - yes, ultimately just a matter of coding style, but I feel it adds a little bit of clarity when viewing code outside an IDE where you don't have the tools to help you.Crew
Just adding my two cents (only a year later), this ordering problem everyone is dancing around is called the Dining Philosophers Problem: en.wikipedia.org/wiki/Dining_philosophers_problemProudfoot

© 2022 - 2024 — McMap. All rights reserved.