Talk:Double-checked locking

Page contents not supported in other languages.
From Wikipedia, the free encyclopedia

With JVM1.5, using the keyword final and the idiom of eager initialization, you shouldn't need to do double-checked locking to create singleton any more. It is as simple as just declared a field final, and JVM will guarantee the the field is visible only after fully initialized. Pls see link below. AltosAce (talk) 17:55, 7 August 2010 (UTC)[reply]

  * http://www.javamex.com/tutorials/synchronization_final.shtml
  * http://renaud.waldura.com/doc/java/final-keyword.shtml


Double Checked Locking works with a ReadWriteLock in Java. The read lock is obtained, the value is checked, and if a write is necessary, the read lock is released and the write lock is obtained. The check must be performed again before writing because another thread may have obtained the write lock in the meantime. Finally the write lock is downgraded to a read lock, and the read lock (either way) is released. http://weblogs.java.net/blog/2006/09/11/rechecking-double-checking 65.82.131.225 (talk) 21:06, 19 April 2010 (UTC)[reply]

Please also see: http://java.sun.com/developer/technicalArticles/Programming/singletons/ This web site also confirms that the only way to solve the singleton pattern problem when using multiple threads in Java is by making the constructor synchronized. —Preceding unsigned comment added by Thosylve (talkcontribs) 19:16, 3 March 2008 (UTC)[reply]

the proposed solution for DCL in Java with the volatile keyword doesn't work

see here: http://www.javaworld.com/jw-02-2001/jw-0209-double.html?page=1 and here: http://www-128.ibm.com/developerworks/java/library/j-dcl.html and here: http://jcp.org/en/jsr/detail?id=133

Even the referenced source itself states that it does not work yet: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html —Preceding unsigned comment added by Tcorbat (talkcontribs) 09:37, 3 September 2007 (UTC)[reply]


uh, AFAIK double checked locking is broken on JAVA, but it can work nicely in C and C++. the problem is, that in Java, you can't insert the required memory barriers...

Good news, Mr./Mrs. 84.157.213.97, perhaps you could add the details to the article? Seriously, I think the article should make clear how it applies to different languages, and should include a formal demonstration of how it can fail in a given memory model (or a proof that it cannot fail :)). PJTraill 18:32, 5 March 2006 (UTC) Aha, I realise that since I last looked a number of things have changed... But a summary of which versions x platforms it can work on would be useful. PJTraill 18:46, 5 March 2006 (UTC)[reply]


According to this article it is also problematic in C++. I found this link on the article page. Perhaps it was added after your comment or you just didn't bother to look at it. http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf

Java example which uses “initialized” boolean seems to be broken[edit]

The Java example which uses the boolean variable to check whether the instance has already been initialized seems flawed and non-functional. “instance” and the call of the constructor in no way depends on the value of “initialized”, so the compiler or the virtual machine executing the code might reorder (swap) the two instructions in the synchronized block. (Or does the Java™ Language Specification explicitly prohibit that???) 87.236.198.84 12:33, 17 May 2007 (UTC)[reply]

Indeed, since the JVM can reorder the instructions the example is equivalent to the earlier (helper == null). iirc this is also mentioned in the "The "Double-Checked Locking is Broken" Declaration" article. So this should be removed. Initworks 09:49, 23 May 2007 (UTC)[reply]
Sorry for dummy question but why not:
class Foo { 
   private Helper helper = null;
   private boolean helperInitialized = false;
   public Helper getHelper() {
       if (helperInitialized == false) {
           synchronized(this) {
               if (helperInitialized == false) {
                   // Variant One:
                   helper = new Helper();
                   helperInitialized = helper.toString() != null;// or helper.calcFlag()
                   // Variant Two:
                   try {
                       helper = new Helper();
                   } finally {
                       helperInitialized = true;
                   }
               }
           }
       }
       return helper;
   }
}
--Shurup 06:20, 14 Jule 2007 (UTC)
The code above looks like it solves the problem w/o volatile. --71.192.157.35 (talk) 13:26, 23 April 2009 (UTC)[reply]
A problem is that assignments are not guaranteed to be visible in the same order across different threads. Another thread may never see the updated value of helper, and always return null, or it can see the assignment to helper and helperInitialized before Helper is fully constructed. 217.155.35.160 (talk) 06:42, 3 January 2013 (UTC)[reply]
I believe the following code should also work (with the Helper class having a getThis() method that just returns a reference to this:
class Foo { 
   private Helper helper = null;
   public Helper getHelper() {
       if (helper == null) {
           synchronized(this) {
               if (helper == null) {
                   helper = (new Helper()).getThis();
               }
           }
       }
       return helper;
}
--Kod-meister (talk) 16:35, 7 May 2009 (UTC)[reply]

DCL isn't a "design pattern"[edit]

How is double-checked locking a "design pattern"? It's really just a programming idiom that may happen to be used in the implementation of some patterns. It's easy to see the difference -- applying a pattern takes work, but using this idiom just takes plugging in the variable names of your choice. Anyone disagree?

Java version doesn't really reduce overhead on modern JVMs[edit]

From here: [1]

The whole point of double-checked locking was that it was supposed to be a performance optimization, designed to eliminate synchronization on the common code path, largely because synchronization was relatively expensive in very early JDKs. Not only has uncontended synchronization gotten a lot cheaper since then, but the new changes to the semantics of volatile make it relatively more expensive than the old semantics on some platforms. (Effectively, each read or write to a volatile field is like "half" a synchronization -- a read of a volatile has the same memory semantics as a monitor acquire, and a write of a volatile has the same semantics as a monitor release.) So if the goal of double-checked locking is supposed to offer improved performance over a more straightforward synchronized approach, this "fixed" version doesn't help very much either.

-- nyenyec  17:50, 4 December 2007 (UTC)[reply]

This is not exactly true. Volatile read/writes are cheaper than any locking since locking itself includes at least a CAS (that includes volatile read/write) and owning thread assignment. Using class initialization to avoid double check idiom had its downsides: classes take extra spaces into the perm gen space. Double check pattern is not a design pattern at any rate. The entire article should be moved away and rewritten. 83.99.131.77 (talk) 22:48, 13 December 2008 (UTC)[reply]

VC++ information seems to be wrong for x86 at least[edit]

volatile keyword does not seem to emit memory barrier instructions on x86 so how can it prevent CPU reordering?

http://bartoszmilewski.wordpress.com/2008/11/05/who-ordered-memory-fences-on-an-x86/ —Preceding unsigned comment added by 86.175.44.87 (talk) 18:03, 8 January 2010 (UTC)[reply]

It looks to me that the Visual C++ version number specified in the article is incorrect. See http://msdn.microsoft.com/en-us/library/12a04hfd%28v=VS.71%29.aspx - this is for Visual Studio .NET 2003 and mentions nothing about ordering. http://msdn.microsoft.com/en-us/library/12a04hfd%28v=VS.80%29.aspx is for Visual Studio 2005 and specifically mentions ordering. Hence the reference to Visual C++ 5.0 should read Visual Studio 2005 I think. SoftwareDave (talk) 14:31, 3 February 2011 (UTC)[reply]

It appears that VC treats volatile as memory barrier as well, at the compiler level, meaning it prevents compiler from reordering memory accesses. I don't think it can prevent CPU reordering without inserting processor-specific memory fences.

C# version should be mentioned as it has been working robustly since 2.0 as well.[edit]

http://msdn2.microsoft.com/en-us/magazine/cc163715.aspx

How about a derivation of the original DCL that avoids using fences in C++?[edit]

(Syntax not checked! Using pthread in this example, but can be any other threading library!)

 class Foo
 { 
 private:
   Helper *helper;
   pthread_key_t localHelper;
   pthread_mutex_t mutex;
 public:
   Foo()
     : helper(NULL)
   {
     pthread_key_create(&localHelper, NULL);
     pthread_mutex_init(&mutex);
   }
   ~Foo()
   {
     pthread_key_delete(&localHelper);
     pthread_mutex_destroy(&mutex);
   }
   Helper *getHelper()
   {
     Helper *res = pthread_getspecific(localHelper);
     if (res == NULL)
     {
       pthread_mutex_lock(&mutex);
       if (helper == NULL)
       {
         helper = new Helper();
       }
       res = helper;
       pthread_mutex_unlock(&mutex);
       pthread_setspecific(localHelper, res);
     }
     return res;
   }
 };

This works because it stores the pointer to the common Helper in a thread-local variable. It has to acquire the lock only the first time the method is called per thread. —Preceding unsigned comment added by Ruestevens (talkcontribs) 09:54, 5 August 2009 (UTC)[reply]

Why not a paragraph about C++11 ?[edit]

For instance, have a look at [2] where use of atomic operations is suggested and illustrated. Ptyxs (talk) 15:11, 4 July 2012 (UTC)[reply]

Why not a paragraph about c++98/03?[edit]

There is still a huge amount of legacy C++98 code still running, being maintained and being written from scratch for that matter. It would be good to have a section describing the situation pre-C++11, i.e. a summary of Meyers and Alexandrescu's article. 160.83.36.129 (talk) 09:17, 27 July 2016 (UTC)[reply]

External links modified[edit]

Hello fellow Wikipedians,

I have just modified 3 external links on Double-checked locking. Please take a moment to review my edit. If you have any questions, or need the bot to ignore the links, or the page altogether, please visit this simple FaQ for additional information. I made the following changes:

When you have finished reviewing my changes, please set the checked parameter below to true or failed to let others know (documentation at {{Sourcecheck}}).

This message was posted before February 2018. After February 2018, "External links modified" talk page sections are no longer generated or monitored by InternetArchiveBot. No special action is required regarding these talk page notices, other than regular verification using the archive tool instructions below. Editors have permission to delete these "External links modified" talk page sections if they want to de-clutter talk pages, but see the RfC before doing mass systematic removals. This message is updated dynamically through the template {{source check}} (last update: 18 January 2022).

  • If you have discovered URLs which were erroneously considered dead by the bot, you can report them with this tool.
  • If you found an error with any archives or the URLs themselves, you can fix them with this tool.

Cheers.—InternetArchiveBot (Report bug) 02:48, 16 December 2016 (UTC)[reply]

Please verify a reference[edit]

Anybody can verify the change of data in this edit special:diff/954987354...? The history of the IP contributions makes me somewhat suspicious. --CiaPan (talk) 10:54, 5 May 2020 (UTC)[reply]

Wrong page number, but I found it. The page number could be different editions or something. Mathnerd314159 (talk) 21:34, 5 August 2023 (UTC)[reply]

Memory order for store?[edit]

The C++ version constructs a lock_guard, then loads with memory_order_relaxed, which makes sense because the mutex-lock provides a memory fence. But then at the end it does s_instance.store(p, std::memory_order_release);. Can't that also be relaxed since it is followed by the RAII mutex unlock? —Ben FrantzDale (talk) 14:21, 9 November 2020 (UTC)[reply]

I thought I understood why, but then I re-read it. If it were a std::atomic<bool> and if we were doing additional work inside the lock, then I think I see why it needs to be s_instance.store(p, std::memory_order_release): While the mutex-unlock is a fence, inside the lock, we need be sure that the store isn't reordered before the other work. However, in this case, the only work is p = new Singleton() and the atomic store, so I don't think (?) the store could be reordered before p = new Singleton() even if it were s_instance.store(p, std::memory_order_relaxed). In the general case, where it's doing other work inside the lock, then I do think s_instance.store(p, std::memory_order_release) is needed. —Ben FrantzDale (talk) 14:14, 11 November 2020 (UTC)[reply]