lock(...) question

  • Thread starter Thread starter wh1974
  • Start date Start date
W

wh1974

Just wondering whether somebody could clarify my understanding on some
code I've seen several times over the past week:

if (m_instance == null)
{
lock (m_syncRoot)
{
if (m_instance == null)
{
m_instance = new Singleton();
}
}
}

I have no problem understanding what the code is doing but I fail to
understand the reason for comparing m_instance to null twice.

Surely the following is equivalent:

lock (m_syncRoot)
{
if (m_instance == null)
{
m_instance = new Singleton();
}
}

Is it just a case of avoiding the call to lock(...) to improve
performance?

Thanks,
Wayne.
 
Just think. Two thread wants to get an instance of your singleton class. One
thread comes and locks m_syncRoot and starts to create instance. At this
time another thread has came and second one also wants to lock. And it will
wait for the first thread. After first thread releases m_syncRoot. Second
one is allowed to lock m_syncRoot. At that time there is an instance of
singleton class.

This will prevent creating instance twice.... Is it clear ?
 
This will prevent creating instance twice.... Is it clear ?

no, it is not clear. the second thread will simply get a reference to the
singleton object of thread A.
The first null check simply avoids the overhead of a lock as you rightly
pointed out. Otherwise, you have a situation where you lock just to read a
variable that
may or may not be null which is needlessly expensive. You test the reference
again for safety inside the critical section since the examining thread is
the only thread that holds a reference to
the object inside an executing application domain. You would need a stronger
lock (mutex etc) if the singleton reference were exposed to multiple
processes or app domains.

--
Regards,
Alvin Bruney [MVP ASP.NET]

[Shameless Author plug]
The Microsoft Office Web Components Black Book with .NET
Now Available @ http://tinyurl.com/27cok
 
Yunus Emre ALPÖZEN said:
Just think. Two thread wants to get an instance of your singleton class. One
thread comes and locks m_syncRoot and starts to create instance. At this
time another thread has came and second one also wants to lock. And it will
wait for the first thread. After first thread releases m_syncRoot. Second
one is allowed to lock m_syncRoot. At that time there is an instance of
singleton class.

This will prevent creating instance twice.... Is it clear ?

It's certainly not as clear as that - the double checked locking
pattern doesn't work in .NET unless you use a volatile variable.

See http://www.pobox.com/~skeet/csharp/singleton.html
 
Yunus Emre ALPÖZEN said:
Just think. Two thread wants to get an instance of your singleton class.
One thread comes and locks m_syncRoot and starts to create instance. At
this time another thread has came and second one also wants to lock. And
it will wait for the first thread. After first thread releases m_syncRoot.
Second one is allowed to lock m_syncRoot. At that time there is an
instance of singleton class.

This will prevent creating instance twice.... Is it clear ?

Of course, but the question was different. It looks like the poster
understands why a lock is necessary but wonders why the (m_instance == null)
test is done twice!

This is a common pattern called "double-checked locking" and the goal is to
improve performance and avoid an extra acquire/release on the lock.

"double-checked locking is actually a controversial technique. There was a
famous article
(http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html)
that demonstrated that double-checked locking is not as safe as it looks, at
least in Java. I have read somewhere that double-checked locking is safe in
..NET because .NET has a slightly different memory model than Java (and it
may also be safe in the latest Java versions). But I suggest that you google
for "double checked locking" to get all the details.

Bruno.
 
Bruno Jouhier said:
Of course, but the question was different. It looks like the poster
understands why a lock is necessary but wonders why the (m_instance == null)
test is done twice!

This is a common pattern called "double-checked locking" and the goal is to
improve performance and avoid an extra acquire/release on the lock.

"double-checked locking is actually a controversial technique. There was a
famous article
(http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html)
that demonstrated that double-checked locking is not as safe as it looks, at
least in Java. I have read somewhere that double-checked locking is safe in
.NET because .NET has a slightly different memory model than Java (and it
may also be safe in the latest Java versions). But I suggest that you google
for "double checked locking" to get all the details.

It's only safe in .NET if the relevant variable is declared as being
volatile - which it usually isn't in the examples given.

Personally I think it's one of those things which should be avoided.
Threading is complicated enough without trying tricks like this - just
use the simplest code (either a type initializer or a lock each time).
 
Jon Skeet said:
It's only safe in .NET if the relevant variable is declared as being
volatile - which it usually isn't in the examples given.

Personally I think it's one of those things which should be avoided.
Threading is complicated enough without trying tricks like this - just
use the simplest code (either a type initializer or a lock each time).

I have the same approach. I'd rather concentrate on high level design,
choice of algorithm, than on micro-optimization. So, I don't use the
double-checked lock idiom, but I think that it is good to know that it has
problems because this is a great example of how trick multi-threading can
be.

Bruno.
 
Chris Brumme, have given convincing reasons why it doesn't
anybody got a link to this?

--
Regards,
Alvin Bruney [MVP ASP.NET]

[Shameless Author plug]
The Microsoft Office Web Components Black Book with .NET
Now Available @ http://tinyurl.com/27cok
----------------------------------------------------------


Yunus Emre ALPÖZEN said:
Just think. Two thread wants to get an instance of your singleton class.
One
thread comes and locks m_syncRoot and starts to create instance. At this
time another thread has came and second one also wants to lock. And it
will
wait for the first thread. After first thread releases m_syncRoot. Second
one is allowed to lock m_syncRoot. At that time there is an instance of
singleton class.

This will prevent creating instance twice.... Is it clear ?

It's certainly not as clear as that - the double checked locking
pattern doesn't work in .NET unless you use a volatile variable.

See http://www.pobox.com/~skeet/csharp/singleton.html
 
I found this the other day on MS's Double-Checked pattern in C# at:
http://msdn.microsoft.com/library/d...n-us/dnpatterns/html/ImpSingletonInCsharp.asp
Uses the volatile. It is interesting as I have read even volatile does not
work correctly (may not) using the DCL in java, but MS claims this works
correctly under .Net.

--
William Stacey, MVP
http://mvp.support.microsoft.com

Yunus Emre ALPÖZEN said:
Just think. Two thread wants to get an instance of your singleton class. One
thread comes and locks m_syncRoot and starts to create instance. At this
time another thread has came and second one also wants to lock. And it will
wait for the first thread. After first thread releases m_syncRoot. Second
one is allowed to lock m_syncRoot. At that time there is an instance of
singleton class.

This will prevent creating instance twice.... Is it clear ?

It's certainly not as clear as that - the double checked locking
pattern doesn't work in .NET unless you use a volatile variable.

See http://www.pobox.com/~skeet/csharp/singleton.html
 
Oppss.. you are right. Sorry for that. I confused something different...

--
Thanks,
Yunus Emre ALPÖZEN



Bruno Jouhier said:
Yunus Emre ALPÖZEN said:
Just think. Two thread wants to get an instance of your singleton class.
One thread comes and locks m_syncRoot and starts to create instance. At
this time another thread has came and second one also wants to lock. And
it will wait for the first thread. After first thread releases
m_syncRoot. Second one is allowed to lock m_syncRoot. At that time there
is an instance of singleton class.

This will prevent creating instance twice.... Is it clear ?

Of course, but the question was different. It looks like the poster
understands why a lock is necessary but wonders why the (m_instance ==
null) test is done twice!

This is a common pattern called "double-checked locking" and the goal is
to improve performance and avoid an extra acquire/release on the lock.

"double-checked locking is actually a controversial technique. There was a
famous article
(http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html)
that demonstrated that double-checked locking is not as safe as it looks,
at least in Java. I have read somewhere that double-checked locking is
safe in .NET because .NET has a slightly different memory model than Java
(and it may also be safe in the latest Java versions). But I suggest that
you google for "double checked locking" to get all the details.

Bruno.
 
Back
Top