Kaz Kylheku <217-679-0842@kylheku.com>: Feb 26 07:14PM >> > d. something else I haven't thought of? >> It must work. > Well, I realize that's what the docs seem to imply, but… The docs clearly require it; if it doesn't work, it's an implementation bug. >> contrast, the PTHREAD_MUTEX_INITIALIZER is described as a macro >> that can be used for initialization, and not a constant. > Sure, but when I assign it, I am doing nothing to ensure that assignment is visible to all threads before they call pthread_once on it. Therefore it seemed plausible that another core's cache still contains some other value for that memory location, and a thread running on that core and calling pthread_once would see the uninitialized value instead of PTHREAD_ONCE_INIT, and skip calling the initialization function, which would be a problem… This depends on how the threads acquire the pointer to this entire object that contains the "pthread_once_t". Suppose that we dynamically allocate "struct point { int x, y; }" and initialize x and y, then pass this on to other threads. How do we ensure that the memory is synchronized so that threads see the stable values of x and y? Whatever approaches works for these x and y is applicable to the initialization of a pthread_once_t. If we just allocate an object, initialize it, put its pointer into an unprotected shared variable which another thread notices has become non-null and uses it, and do not execute any memory barriers, then we have a problem on some machines. If some synchronization is involved then we should be okay. E.g. consumer is waiting on a condition variable for the pointer to materialize and then uses it. static obj *ptr; // assumed initially null // producer new_object->once = PTHREAD_ONCE_INIT; pthread_mutex_lock(&mut); ptr = new_object; pthread_mutex_unlock(&mut); pthread_cond_broadcast(&cond); // consumer pthread_mutex_lock(&mut); while (ptr == 0) pthread_cond_wait(&cond, &mut); pthread_mutex_unlock(&mut); pthread_once(&ptr->once, init_fun); Here, the memory synchronizing properties of the mutex ensure that all the assignments done prior to the producer's pthread_mutex_unlock call are visible at the time the consumer acquires the mutex and finds ptr not to be null. The consumer cannot find a non-null ptr, such that ptr->once has not yet been initialized. If you don't use synchronization like this when introducing the pointer to the other threads, then you're on your own; but it's not really an issue of the pthread_once, but rather an issue of the the reordering of the loads and stores of "ptr" and "ptr->once". > Hm, you make a good point. But you know how tricky races are; I > wouldn't count on all that exercise to have flushed out a bug if this > issue wasn't totally considered. But, come to think of it, is this situation really protected in all circumstances? Suppose thread A obtains a handle with dlopen, passes it unsafely to thread B (e.g. just puts it into a shared location where B picks it up, no mutexes). Is it guaranteed that B can use dlsym, etc, to read the stable value of a global variable variable? I think, if so, it's only because some mutexes are incidentally used inside dlopen, like to insert the library into some global list of loaded libraries. [I apologize for this topical interruption and now return you to the regular deluge of drivel by the local troll.] |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.programming.threads+unsubscribe@googlegroups.com. |
No comments:
Post a Comment