5 ms·
Totally! I was going to post the same thing. Double-checked locking is either impossible or really hard to get right, depending on the language and architectu
by skrap 11y ago
Totally! I was going to post the same thing. Double-checked locking is either impossible or really hard to get right, depending on the language and architecture's guarantees!
If you must use a singleton, I'd really recommend doing the so-called "aggressive" approach, which should have really been named the "actually won't crash sometimes" approach.
- Manishearth 11y agoOn C++ if we're using a bool as the "check" and pthread_mutex_lock on a regular mutex would that work, or do we still need to hardcode fences? (Asking because this pattern is used by libcxxabi code)
- millstone 11y agoYes, this is broken on certain architectures like PPC. Another core may see the "check" bool as set, but the fields of the protected object as uninitialized. One way to address this is to insert a write barrier just before setting the check bool, and a read barrier just after reading it.
- maxlybbert 11y agoA few years ago, the C++ standard didn't guarantee that the double-checked idiom would work. Even if your threading library had some way to insert the necessary memory barriers, it was possible that your compiler would optimize important things away. C++11 changes that. The language now has standard ways to add memory barriers, and compiler optimizations can't remove them.
- jaytaylor 11y ago+1 for the aggressive approach, mutexes are very fast in go. I got curious and wrote a quick little benchmark test: $ cat bench_test.go package main import ( "sync" "testing" ) func BenchmarkMutex(b *testing.B) { var m sync.Mutex for n := 0; n < b.N; n++ { m.Lock() m.Unlock() } } $ go test -v -bench=. bench_test.go BenchmarkMutex 50000000 24.0 ns/op ok command-line-arguments 1.235s A set of mutex.Lock() & .Unlock() calls takes only 24.0ns on average to complete. Thus it's possible to lock/unlock more than 41 million times per second on the puny 2011 MacBook Air I used for this. My .02c: The post seems like a case of premature optimization. Resource bottlenecks due to too much mutex locking in go does not seem like a case that will be commonly hit. With infinite potential bottlenecks, I don't like to spend my time worrying and fussing over things that are: A) Not yet a problem. B) Unlikely to ever be a problem or give me grief. Worrying about the overhead cost of locking falls squarely into just such a category.
- millstone 11y agoHere's the mutex source: https://golang.org/src/sync/mutex.go https://golang.org/src/sync/mutex.go . The fast path is just a CAS, which of course is going to be fast. But it's also important to know how it performs under contention.
- pcwalton 11y agoBe careful with that benchmark. It's very vulnerable to SROA and constant propagation optimizing it away to nothing. (Doesn't look like Go's compiler optimizations are able to do that based on those numbers, but a modern optimizer will.)
- jsprogrammer 11y agoThis has no contention and is essentially a no-op? Or do I not understand go?
- pcwalton 11y agoIt is a no-op, but Golang's Plan 9-based compilers don't do much optimization, so they aren't able to eliminate it.
- AYBABTME 11y agoTry again with many goroutines trying to lock/unlock in parallel (and GOMAXPROCS>1), the results are quite different!
- hyperpape 11y agoIn modern Java, it's easy enough if you've been shown the pattern. What's hard is understanding/discovering it from first principles.
- hyperpape 11y agoSomeone apparently disliked this comment, but check out http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLo.... Scroll down to "Fixing Double-Checked Locking using Volatile." It's five lines of code without braces, and can be applied without any creativity or reasoning.
- cryon 11y agoYou should use enums for singletons i Java. Simple to write, threadsafe and handles serialization. All with guarantees from the Java language specification.
- hyperpape 11y agoI wasn't actually talking about singletons, just the doublechecked locking pattern. It's also necessary for laziness on objects that are referenced by multiple threads. I tend to think Singletons are a dubious design pattern, like a lot of other people.