Most advice on thread safety involves some variation of the following pattern:
public class Thing
{
private readonly object padlock = new object();
private IDictionary stuff, andNonsense;
public Thing()
{
this.stuff = new Dictionary();
this.andNonsense = new Dictionary();
}
public IDictionary Stuff
{
get
{
lock (this.padlock)
{
if (this.stuff.Count == 0)
this.stuff = this.SomeExpensiveOperation();
return this.stuff;
}
}
}
public IDictionary AndNonsense
{
get
{
lock (this.padlock)
{
if (this.andNonsense.Count == 0)
this.andNonsense = this.AnotherExpensiveOperation();
return this.andNonsense;
}
}
}
// Rest of class...
}
In cases where the get operations are expensive and unrelated, a single locking object is unsuitable because a call to Stuff
would block all calls to AndNonsense
, degrading performance. And rather than create a lock object for each call, wouldn't it be better to acquire the lock on the member itself (assuming it is not something that implements SyncRoot
or somesuch for that purpose? For example:
public IDictionary Stuff
{
get
{
lock (this.stuff)
{
if (this.stuff.Count == 0)
this.stuff = this.SomeExpensiveOperation();
return this.stuff;
}
}
}
Strangely, I have never seen this approach recommended or warned against. Am I missing something obvious?
EDIT 24 May 2010
I have made some extensive changes because I really borked my example. Serves me right for trying to simplify the example too much for clarity.
Summary of edits:
- Locking object in first example is no longer static (my original example was from a static class).
- Fields/properties no longer a string, and initialised in constructor so never null.
- Moved return statement inside the
lock{...}
block.