Singleton pattern - Does early binding (with static variables involved) diminish the need of mutex locks?
Asked Answered
C

5

11

They say that early binding solves the problem of synchronization. I couldn't understand "how". Is this something special to Java or the same applies to C++ too?

so, with this method we actually won't require a mutex lock?

enter image description here

Courier answered 7/5, 2012 at 8:31 Comment(13)
Interesting, never thought of using it that way. I always used the if(instance == null) instance = new Singleton();. Gonna wait to see what the experts have to say thoughGutierrez
The above comment is correct, by this way the memory can be saved. because as and when the first request comes the object will be created.Herron
This may throw some light devarticles.com/c/a/Cplusplus/…Speechless
@DaanTimmer - That alone will allow multiple instances to be created in a multi-threaded environment. Also, other threads may see the reference to the instance before the constructor has completed which might make the object invalid.Willard
@gordatron My question is about the concept clarification first. Then it seems to me that the book is talking about JAVA, so wish to know whether this is all specific to Java, or can be implemented in some way for C++ too?Courier
Head First Design Patterns? Cool book!Stockbreeder
I can't think of a reason why they didn't make that singleton field final. Apart from better enforcing the singleton pattern it could also mean better optimization opportunities by the JVM.Sentry
Cant we make getInstance() method synchronized ?Herron
@BhavikAmbani Ofcourse we can, but then this book says that that can be result in performance issues, so this is a better method according to them.Courier
@AnishaKaul Thats true. But this can be another solution for that.Herron
@BhavikAmbani what do you refer by "this" in your comment?Courier
@AnishaKaul My Solution for the problem.Herron
@BhavikAmbani - The point of the static initializer is to avoid the performance hit due to synchronization in the first place.Willard
S
3

I think they are referring to creating the Singleton instance before starting/creating any threads, thus alleviating the need for synchronization at creation.

EDIT: adding info about C++ and static variables

In C++, static variables are also initialized before execution like David Harkness mentions for Java. One issue with this in C++ can be in embedded environments where calls to malloc/new cant be performed until after the system is initialized, in which case using a Singleton static initializer could be problematic.

Stockbreeder answered 7/5, 2012 at 8:40 Comment(5)
@Anisha, Are you referring to the "David Harkness" that answered your question above which you accepted, or a reference to C++?Stockbreeder
No, I was talking about a C++ reference. But then, I thought I should do some work myself too. :)Courier
@Anisha, if you search in stackoverflow, there are loads of related questions.Stockbreeder
Related to the static variable's initialization? Yes, I have found them. I already deleted my comment of asking about the references. :)Courier
@David, you're right. My point is that if you initialize the singleton before the threads are started, nothing else will be needed for the publication of the instance, like using a static initializer or a mutex. For Java I would think that a static initializer would be the prefered approach, but for c/c++ using one could cause complications.Stockbreeder
W
11

The JVM ensures that each class is fully loaded before allowing any access to it via other threads. This means that all static variables, including uniqueInstance above, at fully instantiated before they can be accessed. This is specific to Java and means you don't need synchronization to protect the publication of the instance.

Willard answered 7/5, 2012 at 8:40 Comment(4)
thanks for the confirmation, and also telling this all is totally specific to "Java".Courier
I think to be totally threadsafe you need to mark the field final. Even though the JVM enforces the initialization of static variables, I believe it's possible for the JVM to not emit a memory barrier, which would mean another thread could observe the static field in an uninitialized state.Kisser
You didn't tell me that static variables are also initialized in C++ before the threads can act up?Courier
There is no JVM or classloader in C++ so my answer was specific to Java.Willard
S
3

I think they are referring to creating the Singleton instance before starting/creating any threads, thus alleviating the need for synchronization at creation.

EDIT: adding info about C++ and static variables

In C++, static variables are also initialized before execution like David Harkness mentions for Java. One issue with this in C++ can be in embedded environments where calls to malloc/new cant be performed until after the system is initialized, in which case using a Singleton static initializer could be problematic.

Stockbreeder answered 7/5, 2012 at 8:40 Comment(5)
@Anisha, Are you referring to the "David Harkness" that answered your question above which you accepted, or a reference to C++?Stockbreeder
No, I was talking about a C++ reference. But then, I thought I should do some work myself too. :)Courier
@Anisha, if you search in stackoverflow, there are loads of related questions.Stockbreeder
Related to the static variable's initialization? Yes, I have found them. I already deleted my comment of asking about the references. :)Courier
@David, you're right. My point is that if you initialize the singleton before the threads are started, nothing else will be needed for the publication of the instance, like using a static initializer or a mutex. For Java I would think that a static initializer would be the prefered approach, but for c/c++ using one could cause complications.Stockbreeder
T
0

The answer is YES!. with this method you will not need a lock for the "get instance"
--Edit--
the reason is that the creation of the object is part of the loading process by the OS which guaranteeing it's loaded before your code is running.
P.s. it will apply to C++ as well.
notes:
1. you wouldn't need the lock for the "get instance" but you may needed if there are shared members of the instance.
2. this is only possible if you don't need parameters for the initialization of the instance.

Technique answered 7/5, 2012 at 8:43 Comment(3)
It will be helpful if you could explain why and how too. Simple yes and no don't help too much.Courier
the question was "so, with this method we actually won't require a mutex lock?" so the answer is yes (-: the reason is that the creation of the object is part of the loading process by the OS which guaranteeing it's loaded before your code is running.Technique
The question also contained this statement: "I couldn't understand "how"." Please put your reason in the "answer" to make it somewhat complete.Courier
C
0

One of the things the lazy instantiation tried to solve (not only C++ related) was the static initialization order fiasco. This is a problem that you have little control over the order of initialization (with multiple translation units), but dependencies might require an object to already exist before the other can be created. With lazy instantiation, the object is created as needed, so as long as there is no circular dependency, you should be okay.

If dependencies are an issue for you and you still want to avoid the cost of locking for each getInstance(), you can still do eager instantiation by initializing all your singletons before starting your threads by adding an Initialize() function to your classes. This way you can check with asserts that singletons are only initialized once and only accessed after they are initialized.

Remark that:

  • shared resources should still be locked when they are accessed.
  • from C++11 on (and when using gcc as I'm not sure about other compilers), the easiest solution is to use a static function variable in getInstance and to return a reference to that variable. This is thread-safe.

    class Example
    {
      ...
      static Example& getInstance()
      {
        static Example instance;
        return instance;
      }
    };
    
Cymry answered 7/5, 2012 at 11:28 Comment(0)
B
-2

In case that you want that the singelton member will remain null until first call, you can sync only the creation. for example

getInstance() {
     if (singleton == null) {
         lock();
         if (singleton == null) {
               singleton = new Singleton();
         }
         unlock();
     }
     return singleton;
}
Blinding answered 7/5, 2012 at 8:38 Comment(3)
This code is wrong and dangerous. See en.wikipedia.org/wiki/Double-checked_lockingRosemare
Your solution isn't thread safe. It would be if you made the lock() call before the (singleton == null) check, and the unlock() call after the if block but that would add the lock()/unlock() overhead to every getInstance() call.Enculturation
-1 As interjay noted, this code and the related double-checked locking are not thread-safe.Willard

© 2022 - 2024 — McMap. All rights reserved.