I'm having trouble synchronizing a master thread to a recently started child thread.
What I want to do is:
My first attempt was something like:
  typedef struct threaddata_ {
    int running;
  } threaddata_t;
  void*child_thread(void*arg) {
    threaddata_t*x=(threaddata_t)arg;
    /* ... INITIALIZE ... */
    x->running=1; /* signal that we are running */
    /* CHILD THREAD BODY */
    return 0;
  }
  void start_thread(void) {
    threaddata_t*x=(threaddata_t*)malloc(sizeof(threaddata_t));
    x->running=0;
    int result=pthread_create(&threadid, 0, child_thread, &running);
    while(!x->running) usleep(100); /* wait till child is initialized */
    /* MAIN THREAD BODY */
  }
Now I didn't like this at all, because it forces the main thread to sleep for probably a longer period than necessary. So I did a 2nd attempt, using mutexes&conditions
  typedef struct threaddata_ {
    pthread_mutex_t x_mutex;
    pthread_cond_t  x_cond;
  } threaddata_t;
  void*child_thread(void*arg) {
    threaddata_t*x=(threaddata_t)arg;
    /* ... INITIALIZE ... */
    pthread_cond_signal(&x->x_cond); /* signal that we are running */
    /* CHILD THREAD BODY */
    return 0;
  }
  void start_thread(void) {
    threaddata_t*x=(threaddata_t*)malloc(sizeof(threaddata_t));
    pthread_mutex_init(&x->x_mutex, 0);
    pthread_cond_init (&x->x_cond , 0);
    pthread_mutex_lock(&x->x_mutex);
    int result=pthread_create(&threadid, 0, child_thread, &running);
    if(!result)pthread_cond_wait(&x->x_cond, &x->x_mutex);
    pthread_mutex_unlock(&x->x_mutex);
    /* MAIN THREAD BODY */
  }
This seemed more sane than the first attempt (using proper signals rather than rolling my own wait loop), until I discovered, that this includes a race condition: If the child thread has finished the initialization fast enough (before the main thread waits for the condition), it will deadlock the main thread.
I guess that my case is not so uncommon, so there must be a really easy solution, but I cannot see it right now.
Proper way of condvar/mutex pair usage:
bool initialised = false;
mutex mt;
convar cv;
void *thread_proc(void *)
{
   ...
   mt.lock();
   initialised = true;
   cv.signal();
   mt.unlock();
}
int main()
{
   ...
   mt.lock();
   while(!initialised) cv.wait(mt);
   mt.unlock();
}
This algorithm avoids any possible races. You can use any complex condition modified when mutex locked (instead of the simple !initialised).
The correct tool for that are sem_t. The main thread would initialize them with 0 and wait until it receives a token from the newly launched thread.
BTW your mutex/cond solution has a race condition because the child thread is not locking the mutex.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With