Re: C++ Function Static Initialization, Thread-Safe?



"Chris M. Thomasson" <no@xxxxxxxxxxxx> writes:

Here is a program that illustrates the problem nicely:
__________________________________________________________________
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>


static pthread_once_t g_once = PTHREAD_ONCE_INIT;
static pthread_mutex_t g_mtx = PTHREAD_MUTEX_INITIALIZER;
static sem_t g_in_init;


void init(void) {
sem_post(&g_in_init);
puts("Thread waiting in init routine for `g_mtx'...");
pthread_mutex_lock(&g_mtx);
pthread_mutex_unlock(&g_mtx);
}


void* thread(void* state) {
pthread_once(&g_once, init);
return 0;
}


int main() {
pthread_t tid;
sem_init(&g_in_init, 0, 0);
pthread_mutex_lock(&g_mtx);
puts("Main thread has `g_mtx'...");
pthread_create(&tid, NULL, thread, NULL);
sem_wait(&g_in_init);
puts("Main thread waiting for init routine to finish...");
pthread_once(&g_once, init);
pthread_mutex_unlock(&g_mtx);
pthread_join(tid, NULL);
sem_destroy(&g_in_init);
return 0;
}

__________________________________________________________________



OUCH! There is no way around this. Your 100% correct that the
semantics need to be worked out. Perhaps there should be a guideline
that says you cannot take a mutex in the `init()' routine. Or perhaps
you cannot hold a mutex during a call to `pthread_once()'. This would
translate to C++ in that you cannot take a mutex in the ctor of an
object that may be used as a singleton. Or you cannot hold a mutex
before you make a call into the `instance()' function of a singleton.

Yes, this will deadlock. It's just a problem of waiting for something
whilst holding a lock, if the thing you are waiting for might need to
acquire the lock you hold.

The same applies with mutexes in general --- don't acquire a second
mutex whilst holding one in case another thread tries to acquire them
in the opposite order. It also applies to joining threads --- don't
join a thread whilst holding a mutex if that thread could try and
acquire the mutex.

I think I'd go for not acquiring locks in the once routine, as you
shouldn't need them too often, but IMHO the general guideline is
enough.

Anthony
--
Anthony Williams | Just Software Solutions Ltd
Custom Software Development | http://www.justsoftwaresolutions.co.uk
Registered in England, Company Number 5478976.
Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL
.



Relevant Pages

  • Re: pthread_cond_wait and testing condition explicitly
    ... void wait_for_0_value { ... The waiting thread has released the mutex while it is suspended (you ... When a thread finally signals cond_broadcast, ...
    (comp.unix.programmer)
  • Re: Mutex deadlock problem (fixed line length)
    ... > an RTOS because my little OS did not do preemption. ... > make this work task A uses a mutex. ... > waiting on the mutex 4 B waits for another message 5 A ... Invokes the scheduler ...
    (comp.realtime)
  • Re: Make Single Instance in C#
    ... As for the option of using mutex, we could use ChannelServices to register ... and then exit the second instance. ... public partial class Form1: Form ... delegate void MethodCallback; ...
    (microsoft.public.dotnet.framework)
  • Re: [newbie] conditions: signal sent before waiter available?
    ... With a condition variable is a mutex associated. ... In the book, some examples demonstrate condition variables, waiting for signals, sending signals and awakening. ... So the usuale pattern to wait for a predicate is to lock the mutex that synchronize the access to the predicate and than check if that predicate is true. ...
    (comp.programming.threads)
  • Re: pthread_mutex_unlock (was Re: sched_yield() makes OpenLDAP slow)
    ... > and it getting the mutex first. ... > and an implementation that has the allegedly non-compliant behavior. ... if it goes up then the waiting thread in really ... > Please read the FAQ at http://www.tux.org/lkml/ ...
    (Linux-Kernel)