3

I posted an earlier question about returning collections, and the topic of thread safety came up. I was given this link to do some more reading, and I found this particular line:

In general, avoid locking on a public type, or instances beyond your code's control.

First, correct me if I'm wrong, but doesn't the example that Microsoft give lock on a public type, the balance variable?

Secondly, how would I go about locking my own getter/setter property. Suppose I have the following class:

private int ID;

public Person(int id)
{
    this.Identification= id;

}

public int Identification
{
    get { return this.ID; }

    private set
    {
        if (value == 0)
        {
            throw new ArgumentNullException("Must Include ID#");
        }
        this.ID = value;
    }
}

The getter is public correct? Only the setter is declared private. So, how would I lock, or make my getter/setter properties thread safe?

Community
  • 1
  • 1
  • I suppose you `lock` the backing field, because this will be set by the class itself. – Melvin Jun 09 '15 at 14:25
  • Don't _ever_ lock on value types - make sure you lock only on reference types when you lock. In this example, `ID` is a value type. – xxbbcc Jun 09 '15 at 14:26
  • 1
    I deal with threading a lot at work. The primary reason I cite for not locking an exposed object (e.g. lock(this)) is that you never know when some developer is going to lock it's instance of 'this'. The solution is simple. Create an internal object (e.g. private object mutex = new object()) and use that for locking, don't lock with 'this' or a public property. – Trevor Ash Jun 09 '15 at 14:28
  • Note that locking on a getter/setter very rarely adds 'thread safety' in and of itself. It might be necessary in some cases (such as Int64 values being written from multiple places concurrently), but usually thread safety requires higher level design decisions about how to coordinate multiple reads/writes. – Dan Bryant Jun 09 '15 at 14:39
  • @Atoms - When the article says "n general, avoid locking on a public type, or instances beyond your code's control", it means the object your using the lock must be private, correct? So, your case it would be as you said private object mutex = new object() –  Jun 09 '15 at 14:41

3 Answers3

4

you should define a variable in Person class like this

private readonly object _lock_ = new Object();

if you want to make synchronization over all instances of Person you should make it static.

then when you want to lock you can do it like this

lock(_lock_) //whose there? it's me, I kill you! oops sorry that was knock knock
{
    //do what you want
}

I suggest you to read this article: 1

Spikeh
  • 3,540
  • 4
  • 24
  • 49
Hamid Pourjam
  • 20,441
  • 9
  • 58
  • 74
1

When you need to lock on a variable, you need to lock around every place where the variable is used. A lock is not for a variable - it's for a region of code where a variable is used.

It doesn't matter if you 'only read' in one place - if you need locking for a variable, you need it everywhere where that variable is used.

An alternative to lock is the Interlocked class - this uses processor-level primitives for locking that's a bit faster. Interlocked, however cannot protect multiple statements (and having 2 Interlocked stataments is not the same as having those 2 statements inside a single lock).

When you lock, you must lock on an instance of a reference type (which, in most cases (but not always), should also be a static instance). This is to ensure that all locks are actually taken out on the same instance, not a copy of it. Obviously, if you're using a copy in different places, you're not locking the same thing so your code won't be correctly serialized.

For example:

private static readonly object m_oLock = new object ();

...

lock ( m_oLock )
{
    ...
}

Whether it's safe to use a non-static lock requires detailed analysis of the code - in some situations, it leads to more parallelism because the same region of code is locked less but the analysis of it could be very tricky - if you're unsure, just use a static lock object. The cost of taking an open lock is minimal but incorrect analysis may lead to errors that take ages to debug.

Edit:

Here's an example showing how to lock property access:

private int ID; // do NOT lock on value type instances
private static readonly object Lock = new object ();

public Person(int id)
{
    this.Identification = id;
}

public int Identification
{
    get
    { 
        lock ( Lock )
        {
            return this.ID;
        }
    }

    private set
    {
        if (value == 0)
            throw new ArgumentNullException("Must Include ID#");

        lock ( Lock )
        {
            this.ID = value;
        }
    }
}

Since your property only does a trivial get/set operation, you can try using Interlocked.CompareExchange instead of a full lock - it will make things slightly faster. Keep in mind, though, that an interlocked operation is not the same as a lock.

Edit 2:

Just one more thing: a trivial get / set on an int doesn't need a lock - both reading and writing a 32-bit value (in and of itself) is already atomic. So this example is too simple - as long as you're not trying to use ID in multiple operations that should be completed in an atomic fashion, the lock is not needed. However, if your real code is actually more complicated with ID being checked and set, you may need locking and you'll need to lock around all the operations that make up the atomic operation. This means that you may have to pull the lock out of the getter / setter - 2 locks on a get/set pair of a variable is not the same as a single lock around them.

xxbbcc
  • 16,930
  • 5
  • 50
  • 83
  • Could by any chance alter your code to use my example code, just for my own understanding, the lock would be embedded in the getter/setter property? –  Jun 09 '15 at 14:38
  • @Nexusfactor I added a comment to the answer about when a lock is needed. – xxbbcc Jun 09 '15 at 15:00
  • @xxbbcc: I actually have to disagree with that last edit. The fact that the modified value is an `int`, and can be read/written atomically, doesn't automatically make it thread safe to use. If the `Person` class were mutable, I would still have to use some form of locking, even if the property is an `int`. Let me know if I need to explain myself further. – sstan Jun 09 '15 at 15:06
  • @sstan You're right but I also made it clear that locking can only be avoided if there's no connected reads / writes. If all reads and writes are disconnected, a lock won't do much but we're also talking about trivial code. – xxbbcc Jun 09 '15 at 15:20
1

The answer to your first question about the Microsoft article: No. The article doesn't lock on the balance variable. It locks on the private thisLock variable. So the example is good.

Secondly, based on the code you have posted, you don't need to add any locking to make your class thread safe, because your data is immutable. Once you create an instance of Person and set the value for the Identification property from within the constructor, your class design doesn't allow for that property to change again. That's immutability, and that in itself provides thread safety. So you don't need to bother with adding locks and such. Again, assuming your code sample is accurate.

EDIT: This link may be useful to you.

Community
  • 1
  • 1
sstan
  • 35,425
  • 6
  • 48
  • 66
  • sstan - I think you did me a great favor when posting this. I was confused at first about mutable and immutable type. My class and the getter/setter properties are all designed like this anyway. –  Jun 09 '15 at 14:50
  • Just for my own understanding, in order too change it, you would have to gather the necessary values, declare a new person object, and then change the value that's necessary, correct? –  Jun 09 '15 at 14:52
  • 1
    Not sure I understand that last question, and I worry you might be misunderstanding me. So let me rephrase that. As long as your class sets the properties from within your constructor, and there is no way to change the properties once your class is constructed, then you've achieved immutability, and don't need anything more to make it thread safe. If you *can* set properties after constructing an object, then you should add locking as suggested in the other answers. Does that clear things up? – sstan Jun 09 '15 at 14:55
  • Yes it does, I just wondering, lets say in my person class, I have firstname, last name. Now, the person decides to change his/her firstname, I can't access the setter from outside the class. To change it, I would have to declare a new person object, gather the values that didn't change,change the necessary value, and store it. Correct? I'm not making a change on my previously created object, and by what you've posted, should be thread-safe to begin with, provides the setters are private. –  Jun 09 '15 at 14:58
  • Great! If, like you describe, in order to change a value in a `Person` instance, you force yourself to create a brand new `Person` instance with the modified properties, then you are still dealing with immutable objects, and so your `Person` class is thread safe with no further special action on your part. – sstan Jun 09 '15 at 15:01
  • @Nexusfactor Create immutable classes and when you need to update a property, just create a new instance with the new value. This is why `String` is immutable - once the object is created (on one thread) it cannot be changed so there're no threading issues. – xxbbcc Jun 09 '15 at 15:02
  • @xxbbcc and sstan - Thanks, both for your time, code, and explanations. Much appreciated. –  Jun 09 '15 at 15:03