Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.programming.threads > #1331
| Date | 2013-02-06 14:39 +0100 |
|---|---|
| From | Marcel Müller <news.5.maazl@spamgourmet.org> |
| Newsgroups | comp.programming.threads |
| Subject | Re: Double check locking - are release and acquire fences enough for C++ memory model? |
| References | <9b219fb9-0b51-4c06-9398-d1e7ab878f7d@googlegroups.com> <511207c5$0$6565$9b4e6d93@newsspool3.arcor-online.net> <225a96b2-e794-43c7-b82a-64a69c2cb626@hq4g2000vbb.googlegroups.com> |
| Message-ID | <51125d0d$0$6572$9b4e6d93@newsspool3.arcor-online.net> (permalink) |
| Organization | Arcor |
On 06.02.13 13.40, Michael Podolsky wrote:
>> I am a bit confused. None of these atomic operations are required if we
>> are talking about double check. The idea of double checking is to use an
>> ordinary mutex and to provide a fast path for some frequent cases.
>> Whether the fast path has a race condition or not is unimportant because
>> the mutex will ensure defined behavior.
>
> Let's stop here because if we do not agree about the need of memory
> fences in double check locking fast path, the rest is irrelevant.
> http://erdani.com/publications/DDJ_Jul_Aug_2004_revised.pdf (chapter
> 6) gives some argumentation why memory fences are needed, so is
> http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
> (though related to Java).
You are right. Maybe I did too much x86 and x64 the last time. Memory
reordering is very limited there so I did not run into this pitfall so far.
Additionally I wrote the pseudo code a bit to fast to make it look more
pretty. Usually it looks slightly different and avoids any unnecessary
access to the shared storage.
static T* ptr = NULL;
static Mutex mtx;
T* get_singleton_T()
{ T* tmp = ptr;
if (tmp) // First check, race condition accepted
return tmp;
mtx.lock(); // wait for mutex, full mem bar
tmp = ptr;
if (tmp) // the double check
{ mtx.release(); // release mutex, full mem bar
return tmp;
}
tmp = new T(); // create singleton
mtx.release(); // release mutex, full mem bar
return ptr = tmp;
}
This prevents the accidental access to uninitialized members of T.
The side effect, that the change to ptr may never propagate to other
CPUs only causes some additional lock/release.
Maybe there are platforms where Mutex lock/release does not ensure cache
coherence. In this case you are right and a synchronized access is
always required, even in case the object has been initialized long before.
But I can's see why release/acquire should /not/ be sufficient in this
cases. So to reply to your original question, I do not see a scenario
where the use of two dependent singletons with double checked
initialization end up in undefined behavior as long as each of the
double checks is implemented correctly.
Of course, one race will never disappear. If writing or reading a
pointer is not implicitely atomic, then double check makes no sense for
pointers. In this case even memory barriers won't help. But in the last
25 years I have never developed on a platform where this was not
satisfied. MC68k, Alpha, T80x, x86-32 and x86-64 met the condition. And
with platforms without atomic pointer access one could use an additional
boolean to keep the initialized flag.
In practice I have some use cases where the singleton is immutable,
reproducible and only for performance reason of singleton type. (Things
like string.Empty) In this cases I use an even more ugly version without
any locking:
class T
{ static T ptr = null;
public T instance
{ get
{ if (!ptr)
ptr = new T();
return ptr;
}
}
}
Of course, this makes only sense for languages with a GC like .NET. But
with the costraint that every new T() will produce a logically
equivalent object and, of course, pointers are implicitly atomic, it
will not result in undefined behavior. In worst case it may create as
many objects as there are threads and/or CPUs. But this can still be
only a slight overhead compared to thousands of objects created otherwise.
Marcel
Back to comp.programming.threads | Previous | Next — Previous in thread | Next in thread | Find similar
Double check locking - are release and acquire fences enough for C++ memory model? Michael Podolsky <michael.podolsky.69@gmail.com> - 2013-02-04 23:09 -0800
Re: Double check locking - are release and acquire fences enough for C++ memory model? Marcel Müller <news.5.maazl@spamgourmet.org> - 2013-02-06 08:35 +0100
Re: Double check locking - are release and acquire fences enough for C++ memory model? Michael Podolsky <michael.podolsky.69@gmail.com> - 2013-02-06 04:40 -0800
Re: Double check locking - are release and acquire fences enough for C++ memory model? Marcel Müller <news.5.maazl@spamgourmet.org> - 2013-02-06 14:39 +0100
Re: Double check locking - are release and acquire fences enough for C++ memory model? Michael Podolsky <michael.podolsky.69@gmail.com> - 2013-02-06 19:19 -0800
Re: Double check locking - are release and acquire fences enough for C++ memory model? Gerhard Fiedler <gelists@gmail.com> - 2013-02-06 11:58 -0200
Re: Double check locking - are release and acquire fences enough for C++ memory model? Michael Podolsky <michael.podolsky.rrr@gmail.com> - 2013-04-01 12:12 -0700
csiph-web