Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I use a different object to lock for each property?

I have a class and its properties; the access to these properties is very frequently done by different threads.

It is more efficient use the same object (for the lock statement) for each property?

private readonly object padlock = new object();

private string name;
private int age;

public string Name
{
   get
   {
      lock(padlock)
         return name;
   }

   set
   {
      lock(padlock)
         name = value;
   }
}

public int Age
{
   get
   {
      lock(padlock)
         return age;
   }

   set
   {
      lock(padlock)
         age = value;
   }
}

Or to use a different object for each property?

private readonly object padlockName = new object();
private readonly object padlockAge = new object();

private string name;
private int age;

public string Name
{
   get
   {
      lock(padlockName)
         return name;
   }

   set
   {
      lock(padlockName)
         name = value;
   }
}

public int Age
{
   get
   {
      lock(padlockAge)
         return age;
   }

   set
   {
      lock(padlockAge)
         age = value;
   }
}

The second version makes any sense?

like image 962
Nick Avatar asked Oct 06 '22 20:10

Nick


1 Answers

I hesitate to even answer the question you've asked, because I doubt that either of these locking patterns will ensure correctness in your application. They don't ensure that the object as a whole is kept in a consistent state - they just ensure that individual properties are not updated concurrently. To put it another way, you've implemented atomic reads and writes in a roundabout way.

For example, say you had an operation that would increment Age. If two different threads did that at once, the final result could be (Age + 1) or (Age + 2).

You should most likely remove locking from within the object, and have callers deal with concurrency issues as appropriate. One easy solution is to lock the entire object for the duration of their interaction with it. eg:

lock(myObj){
  myObj.Age++;
  myObj.Name = "Bill";
}

Update

To expand on my middle paragraph, the reason that running Age++ on two different threads could give different results is because the ++ operator is not atomic. It is roughly equivalent to this.

int temp = Age;
temp = temp + 1;
Age = temp;

If two threads ran the same thing, it could execute in order like this (for clarity I've changed names of the temp variables):

int temp1 = Age; //thread 1
int temp2 = Age; //thread 2
temp1 = temp1 + 1;  //thread 1
temp2 = temp2 + 1; //thread 2
Age = temp1; //thread 1
Age = temp2; //thread 2

The purpose of locking is to ensure that one thread runs the entire read-increment-write sequence before the other thread does. But your locking scheme doesn't do that.

like image 131
Brian Reischl Avatar answered Oct 13 '22 10:10

Brian Reischl