Getting a lock using an object, rather than this - Threading

266 views Asked by At

I’m trying to learn threading in C#, and I’ve seen something crop up in few articles but I am not sure I fully understand it: In the given two examples, what would the fundamental difference between getting a lock on ‘this’ vs ‘thisLock’.

Example 1:

class Account
    {
        decimal balance;
        private Object thisLock = new Object();

        public void Withdraw(decimal amount)
        {
            lock (thisLock)
            {
                if (amount > balance)
                {
                    throw new Exception("Insufficient funds");
                }
                balance -= amount;
            }
        }
    }

Example 2:

class Account
    {
        decimal balance;

        public void Withdraw(decimal amount)
        {
            lock (this)
            {
                if (amount > balance)
                {
                    throw new Exception("Insufficient funds");
                }
                balance -= amount;
            }
        }
    }

From my understanding, I would of thought that ‘thisLock’ only stops other threads from entering that specific area of code.

Were as getting a lock on ‘this’ would stop all operations on the object, i.e. calls to other methods by other threads?

Have I fundamentally miss understood this, or is that the correct conclusion?

3

There are 3 answers

0
Marvin Smit On

The difference is locking granularity.

When locking an object, (simplified) a bit is set on the instance. Anyone else trying to lock the same instance will end up in a wait state until the lock is released by the other.

In many cases, methods on a object can be used at the same time (i.o.w. In parallel). Locking the entire object (this) would exclude the usage of any other method if that method also uses 'lock(this)'.

Since lock can be used on any reference type, we can create "lock" objects. Where we implement the 'lock(lockObject)' on a exclusion basis.

As example;

  • MethodA1 and MethodA2 cannot be used at the same time
  • MethodB1 and MethodB2 cannot be used at the same time

  • MethodA1/2 can be used at the same time as MethodB1/2.

If we would use the lock(this) on every method, we would also be exluding MethodA1/2 from running at the same time as MethodB1/2.

By creating 2 lock objects (lockAMethods, lockBMethods) we can now implement our locking more granular.

  • In MethodA1 and MethodA2 we'll use "lock(lockAMethods)" to make sure the A1 and A2 methods cannot run at the same time.
  • In MethodB1 and B2 we'll use the "lock(lockBMethods)" to make sure the B1 and B2 methods cannot run at the same time.

We can however lock(lockAMethods) and lock(lockBMethods) at the same time. Hence we can now run MethodA1/2 at the same time as MethodB1/2.

Hope this helps,

2
viraptor On

Both cases will have the exact same effect. One difference is that other objects cannot see thisLock, so you can be sure nothing else will reuse the lock. If you lock on this, another part of code can also lock on the same instance of Account.

2
Deepak Bhatia On

You stated

From my understanding, I would of thought that ‘thisLock’ only stops other threads from entering that specific area of code.
Were as getting a lock on ‘this’ would stop all operations on the object, i.e. calls to other methods by other threads?

Whether you use lock(this) or lock(thisLock) in both the statements, it will only stops other threads from entering that specific area of code.
But as a general practice it is always advised not to use lock(this) rather create another object and place a lock on that object.

EDIT yes as Sriram Sakthivel has commented, he is absolutely right, please read Why is lock(this) {...} bad? for more information why we should avoid lock(this)