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

< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 

Public Class Configuration

    ' The static instance of this class...

    Private Shared m_Configuration As MyFramework.Configuration = Nothing

 

 

    ' Prevent instantiation...

    Private Sub New()

        MyBase.New()

    End Sub

 

 

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

    Private Shared ReadOnly Property 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_Configuration Is Nothing) Then

                SyncLock m_Configuration  ' tried "Me"

                    If (m_Configuration Is Nothing) Then

                        m_Configuration = New MyFramework.Configuration

                    End If

                End SyncLock

            End If

            Return m_Configuration

        End Get

    End Property

End Class



Answer this question

Singleton Pattern - Shared/Synclock confusion...

  • Virlene Cheng

    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!

  • Pablo Roca

    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!


  • Trangen16a

    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

    ....

     



  • Erfan

    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

  • pidge

    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

     


  • Singleton Pattern - Shared/Synclock confusion...