Singleton Pattern - Shared/Synclock confusion...

Given the code below, I am trying to implement a "double-checked" constructor for a singleton pattern essentially....

What has me confused is how I should handle my locking. In examples I found it often showed the simple "SyncLock Me" approach to lock a section of code. When I try to use this in VB.NET 2005 (Beta 2) I get an error stating that Me isn't allowed for non-instance members. In this case, using a shared constructor, what should I be doing differently?

The code below I've tried to lock on the shared object itself, but on the 1st hit it is 'nothing' which you can't SyncLock on 'nothing'.....

Am I just missing the point or is there something else I need to be aware of?

PublicClass Configuration

' The static instance of this class...

PrivateShared m_ConfigurationAs MyFramework.Configuration =Nothing

' Prevent instantiation...

PrivateSubNew()

MyBase.New()

EndSub

' Provides a thread-safe shared instance of this class...

PrivateSharedReadOnlyProperty MyInstance()As MyFramework.Configuration

Get

' Use the 'double-check' approach to ensure thread-safe singleton construct

' without the SynchLock overhead on 1st 'is nothing' check...

If (m_ConfigurationIsNothing)Then

SyncLock m_Configuration' tried "Me"

If (m_ConfigurationIsNothing)Then

m_Configuration =New MyFramework.Configuration

EndIf

EndSyncLock

EndIf

Return m_Configuration

EndGet

EndProperty

End Class

[8590 byte] By [BradHehe] at [2008-2-27]
# 1

Typically in this situation, people generally tend to lock the Type itself. However, this is incorrect as other external objects can also lock the Type and this could end in a deadlock.

The best thing to do here is to create a private shared object that is specifically used for the lock. No other object external of the Configuration class can lock this object, so deadlocks are avoided. You also want to add the call to Thread.MemoryBarrier() see http://blogs.msdn.com/brada/archive/2004/05/12/130935.aspx)



Private Shared m_ConfigurationLock As New Object()

...

If (m_Configuration Is Nothing) Then

SyncLock m_ConfigurationLock

If (m_Configuration Is Nothing) Then

Dim config as New MyFramework.Configuration()

System.Threading.Thread.MemoryBarrier()

m_Configuration = config

End If

End SyncLock

End If

....

DavidM.Kean at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic Language...
# 2
Thanks! I'll give this a try.

I had already found the 'lock object' approach elsewhere and implemented that and it worked. But I'm glad you've pointed out the MemoryBarrier implementation. I'm no multi-threading guru... just trying to keep my head above water and prevent any problems where I can...

Again, Thanks!

BradHehe at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic Language...
# 3
With the .NET Framework, you do not actually need to use the double-lock approach when creating a singleton object.

You can use this code as a framework:

NotInheritable Class Singleton

Private Sub New()
End Sub

Public Shared ReadOnly Instance as New Singleton

End Class

There actually was a MSDN webcast on design patterns by Craig Utley (which is where the above example came from) earlier today. The webcast was called "Patterns & Practices Live!: Pattern Based Development using the .NET Framework" and should be available in the Webcast archives in several days.

Mr. Utley will be posting his sample code on his web site (www.enterprisesoftwarearchitects.com) today.

Richard Rosenheim

RichardR at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic Language...
# 4
You know, I read that elsewhere too.

So my question is this.. who's right? Or.. are you both right?

Let me repose the question as this...

Given the 2 techniques shared here, one is very explicit and the other leaves the actual work/implementation to the CLR. Normally I would prefer to let the underlying optimizations in the CLR do it's thing I'm pretty sure the CLR guys know better than I do! But, is there anything *wrong* with doing it the other way? I can see there being a small performance hit with the locking and the extra comparisons, but I also like the fact that when someone else looks at my chunk of code they'll get that "ah! ha! he's ensuring thread safety here.. I better watch how I utilize this." moment and possibly prevent them from going down a wrong path.

What I'm hoping for here is that it's simply a preference and not a matter of the right/wrong technique.

On the same note, If I have a property 'getter' in a static class like above and I want to ensure one 1 instance of a contained/shared item do I still need to adhere to the locking strategy above... In other words, I would use the "double-check" to govern both the class instantiation and any contained member instantiation. If that's not clear I'll throw a little snippet of code up to better illustrate what I'm getting at.

Thanks again for the feedback. This reminds me of my old FidoNet days on the Turbo Pascal threads... It's great to have an activity & contributing community like this!

BradHehe at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic Language...
# 5
Both methods should work. Personally, I would use the CLR-based solution -- it's less code that I have to write and debug.

When talking about implementing a singleton object, Mr. Utley actually did demostrate both techniques and stated that they were both functionally equivalent.

Richard Rosenheim

RichardR at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic Language...