Subj : Re: double-checked locking in C To : comp.programming.threads From : Laurent Deniau Date : Wed Jul 06 2005 07:05 pm Joe Seigh wrote: > Laurent Deniau wrote: > >> Joe Seigh wrote: >> >>> No, sorry. The burden of proof is on you. And the reason I posted the >>> URL is so we don't have to disprove every bogus DCL implementation there >>> is over and over again. >> >> >> >> How I can I prove that there is no bogus? If the DCL code shown is so >> easy to break, show me a sequence of actions (points). I can detail >> all steps for different cases, but it will be much longer than showing >> a single bogus case, if any. >> >>> Another URL you can check out >>> http://www.nwcpp.org/Downloads/2004/DCLP_notes.pdf >> >> >> >> Thanks, but at first quick reading, I still do not see problems. >> > > The basic pattern is > > a) store object state > b) store flag > > and > c) read flag > d) read object state > > and dcl depends on if a thread sees the new value of flag, then it will > see all > the new values of the object state. DCL does not involve objects. The problem is that you are addressing two different problems: one is DCL and validity of the *value* of the flag and the other is the side effects of the code in the lock/unlock part which is related to global shared objects and their visibility to other processes, *including* objects related to the semantics of the flag, i.e. pointers. --------- Example 1 DCL pattern with no lock for reading initialized value: *** mult_time.c static unsigned mult_time = 0; /* in pico seconds */ pthread_mutex_t mult_mutex; unsigned get_mult_time(void) { if (!mult_time) { pthread_mutex_lock(&mult_mutex); if (!mult_time) mult_time = compute_mult_time(); pthread_mutex_unlock(&mult_mutex); } return mult_time; } *** compute_mult_time.c unsigned compute_mult_time(void) { chrono_t t0, t1; int a = 2; unsigned i; start_chrono(&t0); for (i = 0; i < 1000000; i++) a = a * a; stop_chrono(&t1); /* note: the value could be read in a file, no difference on the principle */ return time_chrono(t0, t1); } ------- Example 2 DCL pattern with no lock for reading allocated value (semantic of singleton): *** singleton.h struct singleton { int initialized; struct data *data; } *** singleton.c static struct singleton sentinel = {0}; static struct singleton *singleton = &sentinel; pthread_mutex_t singleton_mutex; struct data* get_singleton(void) { if (!singleton->initialized) { pthread_mutex_lock(&singleton_mutex); if (!singleton->initialized) singleton = singleton_factory(); pthread_mutex_unlock(&singleton_mutex); } return singleton->data; } *** singleton_factory.c pthread_mutex_t singleton_factory_mutex; struct singleton* singleton_factory(void) { struct singleton *s; pthread_mutex_lock(&singleton_factory_mutex); s = malloc(sizeof *s); if (!s) abort(); s->data = malloc(sizeof *s->data); if (!s->data) abort(); init_data(s->data); s->initialized = 1; pthread_mutex_unlock(&singleton_factory_mutex); /* note: lock and unlock are only for memory synchronization and are probably redondant with the internal ones of malloc */ return s; } > That depends on (a) occurring before > (b) and on (c) occurring before (d). You haven't shown the former, (a) > occurs before (b). > > That you don't see the problem doesn't prove anything. Show us the > mechanism > that guarantees (a) occurs in memory before (b). If your flag has a semantic of indirection, put the flag state in the pointee. ld. .