I'm perhaps not very polite asking on this list without waiting the usual lurking time, but I've been googling this problem for a while yesterday and I did not find out anything about it. Still the problem is very clear:
I wrote a sort of 'hello world' program where a global mutex is created to synchronize access to a resource shared between a parent and a child process created with a Unix 'fork' call. The child *should* gain the lock first, as the parent is given a 2 seconds wait before attempting to lock the mutex. Then it should release the lock giving way to the parent. That's all. Simply the calls to apr_global_mutex_[lock|trylock|unlock] wait forever and never return. I also thought the apr_global_mutex_create returned an implicitly locked mutex and tried to unlock it. Also this call would block forever. Where did I get it wrong? I asked also other people who are using global mutexes in their projects and they observed the same problem when they run my program and could not give an explanation. The program is so simple that I dare attach it here. It is a way to become familiar with tools that I hope will be used to design and implement a new software component to be developed for Apache Rivet, if this can work as an excuse for my intrusiveness. thanks for any help. -- Massimo Manghi
/* * Concurrency of parent and child processes using apr_global_mutex_* */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <apr-1.0/apr_pools.h> #include <apr-1.0/apr_global_mutex.h> #define MUTEX_NAME "MUTEX" int main(int argc,char** argv) { apr_status_t apr_s; apr_pool_t* aPool; apr_global_mutex_t* mutex_s = NULL; pid_t cpid; apr_s = apr_pool_initialize(); apr_s = apr_pool_create (&aPool,NULL); if (apr_s != APR_SUCCESS) { fprintf (stderr,"....could not initialize the pool...\n"); exit(1); } /* now, we create a global mutex */ apr_s = apr_global_mutex_create (&mutex_s,MUTEX_NAME,APR_LOCK_DEFAULT,aPool); if (apr_s != APR_SUCCESS) { fprintf(stderr,"damn....could not create the mutex\n"); exit(1); } fprintf (stderr,"[p] mutex created\n"); apr_s = apr_global_mutex_child_init(&mutex_s,MUTEX_NAME,aPool); if (apr_s != APR_SUCCESS) { fprintf (stderr,"[p] gasp...could not map the mutex...bye\n"); exit(1); } fprintf (stderr,"[p] acquired map to mutex type '%s'\n",apr_global_mutex_name(mutex_s)); /* Parent and child fork here. The child will be given more chances to gain access to the protected resource as first */ cpid=fork(); if (cpid == 0) { apr_s = apr_global_mutex_child_init(&mutex_s,MUTEX_NAME,aPool); if (apr_s != APR_SUCCESS) { fprintf (stderr,"[c] gasp...could not map the mutex...bye\n"); exit(1); } fprintf (stderr,"[c] acquired map to mutex type '%s'\n",apr_global_mutex_name(mutex_s)); fprintf (stderr,"[c] child proc attempting to lock the mutex...\n"); apr_s = apr_global_mutex_lock(mutex_s); if (apr_s == APR_SUCCESS) { fprintf (stderr,"[c] fallito\n"); exit(1); } fprintf (stderr,"[c] ok, child got the lock!\n"); /* whatever the resource we protect with the mutex the child process can manipulate it here */ sleep(2); apr_s = apr_global_mutex_unlock(mutex_s); if (apr_s != APR_SUCCESS) { fprintf (stderr,"[c] mhhh....unlock fails...why?\n"); exit(1); } fprintf (stderr,"[c] unlocked\n"); } else { /* we give che child process a fair advantage to gain the lock on the mutex */ sleep(2); fprintf(stderr,"[p] parent process attempts to lock the mutex...\n"); apr_s = apr_global_mutex_lock(mutex_s); if (apr_s != APR_SUCCESS) { fprintf (stderr,"failed\n"); exit(1); } fprintf (stderr,"[p] ok, parent got the lock!\n"); /* it's the parent turn to access and manipulate the protected resource */ apr_s = apr_global_mutex_unlock(mutex_s); if (apr_s != APR_SUCCESS) { fprintf (stderr,"[p] mhhh....unlock fails...why?\n"); exit(1); } fprintf (stderr,"[p] mutex unlocked\n"); } fprintf (stderr,"cpid: %d comes here...\n",cpid); exit(0); }