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?
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 theInterlocked
class - this uses processor-level primitives for locking that's a bit faster.Interlocked
, however cannot protect multiple statements (and having 2Interlocked
stataments is not the same as having those 2 statements inside a singlelock
).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:
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:
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 useID
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 withID
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.