Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Share condition variable & mutex between processes: does mutex have to locked before?

Tags:

I need to some little help to understand how to use condition variables in C to resolve an exercise. Here is a little example:

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h>  #define OKTOWRITE "/oktowrite" #define MESSAGE "/message" #define MUTEX "/lock"  int main(int argc, char** argv) {   pthread_cond_t* condition;   pthread_mutex_t *mutex;   char* message;   int des_cond, des_msg, des_mutex;   int mode = S_IRWXU | S_IRWXG;    des_mutex = shm_open(MUTEX, O_CREAT | O_RDWR | O_TRUNC, mode);    if (des_mutex < 0)   {     perror("failure on shm_open on des_mutex");     exit(1);   }    if (ftruncate(des_mutex, sizeof(pthread_mutex_t)) == -1)   {     perror("Error on ftruncate to sizeof pthread_cond_t\n");     exit(-1);   }    mutex = (pthread_mutex_t*) mmap(NULL, sizeof(pthread_mutex_t),       PROT_READ | PROT_WRITE, MAP_SHARED, des_mutex, 0);    if (mutex == MAP_FAILED )   {     perror("Error on mmap on mutex\n");     exit(1);   }    pthread_mutex_init(mutex, NULL );    des_cond = shm_open(OKTOWRITE, O_CREAT | O_RDWR | O_TRUNC, mode);    if (des_cond < 0)   {     perror("failure on shm_open on des_cond");     exit(1);   }    if (ftruncate(des_cond, sizeof(pthread_cond_t)) == -1)   {     perror("Error on ftruncate to sizeof pthread_cond_t\n");     exit(-1);   }    condition = (pthread_cond_t*) mmap(NULL, sizeof(pthread_cond_t),       PROT_READ | PROT_WRITE, MAP_SHARED, des_cond, 0);    if (condition == MAP_FAILED )   {     perror("Error on mmap on condition\n");     exit(1);   }    pthread_cond_init(condition, NULL );    if (!fork())   {     sleep(3);     pthread_mutex_lock(mutex);     pthread_cond_signal(condition);     pthread_mutex_unlock(mutex);     printf("son signaled\n");     exit(0);   }   else   {     printf("wait on condition\n");      pthread_mutex_lock(mutex);     pthread_cond_wait(condition, mutex);     pthread_mutex_unlock(mutex);      printf("Signaled by son process, wake up\n");      pthread_mutex_destroy(mutex);     pthread_cond_destroy(condition);      shm_unlink(OKTOWRITE);     shm_unlink(MESSAGE);     shm_unlink(MUTEX);      return 0;   } } 

The problem is that the father of the process keeps on being locked, even after son's signaling. Everything is in shared memory (using shm_open and mmap) so the condition should be the same for both the processes. Am I maybe making a mistake by locking the mutex before calling wait or signal?

EDIT: Thanks to all who helped me. Here's the right code with the CRITICAL parts marked:

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h>  #define OKTOWRITE "/condwrite" #define MESSAGE "/msg" #define MUTEX "/mutex_lock"  int main(int argc, char** argv) {  pthread_cond_t* condition; pthread_mutex_t* mutex; char* message; int des_cond, des_msg, des_mutex; int mode = S_IRWXU | S_IRWXG;  des_mutex = shm_open(MUTEX, O_CREAT | O_RDWR | O_TRUNC, mode);  if (des_mutex < 0) {     perror("failure on shm_open on des_mutex");     exit(1); }  if (ftruncate(des_mutex, sizeof(pthread_mutex_t)) == -1) {     perror("Error on ftruncate to sizeof pthread_cond_t\n");     exit(-1); }  mutex = (pthread_mutex_t*) mmap(NULL, sizeof(pthread_mutex_t),         PROT_READ | PROT_WRITE, MAP_SHARED, des_mutex, 0);  if (mutex == MAP_FAILED ) {     perror("Error on mmap on mutex\n");     exit(1); }  des_cond = shm_open(OKTOWRITE, O_CREAT | O_RDWR | O_TRUNC, mode);  if (des_cond < 0) {     perror("failure on shm_open on des_cond");     exit(1); }  if (ftruncate(des_cond, sizeof(pthread_cond_t)) == -1) {     perror("Error on ftruncate to sizeof pthread_cond_t\n");     exit(-1); }  condition = (pthread_cond_t*) mmap(NULL, sizeof(pthread_cond_t),         PROT_READ | PROT_WRITE, MAP_SHARED, des_cond, 0);  if (condition == MAP_FAILED ) {     perror("Error on mmap on condition\n");     exit(1); }            /* HERE WE GO */ /**************************************/      /* set mutex shared between processes */ pthread_mutexattr_t mutexAttr; pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED); pthread_mutex_init(mutex, &mutexAttr);  /* set condition shared between processes */ pthread_condattr_t condAttr; pthread_condattr_setpshared(&condAttr, PTHREAD_PROCESS_SHARED); pthread_cond_init(condition, &condAttr);      /*************************************/  if (!fork()) {      sleep(10);      pthread_mutex_lock(mutex);     pthread_cond_signal(condition);     printf("son signaled\n");     pthread_mutex_unlock(mutex);     exit(0); }  else {      printf("father waits on condition\n");       pthread_mutex_lock(mutex);      pthread_cond_wait(condition, mutex);      pthread_mutex_unlock(mutex);       printf("Signaled by son process, wake up!!!!!!!!\n");      pthread_condattr_destroy(&condAttr);     pthread_mutexattr_destroy(&mutexAttr);     pthread_mutex_destroy(mutex);     pthread_cond_destroy(condition);      shm_unlink(OKTOWRITE);     shm_unlink(MESSAGE);     shm_unlink(MUTEX);  }  return 0;  } 
like image 776
SagittariusA Avatar asked Dec 02 '13 09:12

SagittariusA


People also ask

What are conditional variables?

A conditional variable in operating system programming is a special kind of variable that is used to determine if a certain condition has been met or not. It is used to communicate between threads when certain conditions become true. A conditional variable is like a queue.

What are condition variables in monitors?

A condition variable essentially is a container of threads that are waiting for a certain condition. Monitors provide a mechanism for threads to temporarily give up exclusive access in order to wait for some condition to be met, before regaining exclusive access and resuming their task.

What is condition variable in synchronization?

Condition variables are synchronization primitives that enable threads to wait until a particular condition occurs. Condition variables are user-mode objects that cannot be shared across processes. Condition variables enable threads to atomically release a lock and enter the sleeping state.

What does condition variable wait do?

condition_variable::wait wait causes the current thread to block until the condition variable is notified or a spurious wakeup occurs, optionally looping until some predicate is satisfied (bool(stop_waiting()) == true).


2 Answers

To be shareable between processes a mutex needs to be initialised accordingly via a properly initialised attribute: http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setpshared.html

#include <pthread.h>  ...  pthread_mutex_t * pmutex = NULL; pthread_mutexattr_t attrmutex;  /* Initialise attribute to mutex. */ pthread_mutexattr_init(&attrmutex); pthread_mutexattr_setpshared(&attrmutex, PTHREAD_PROCESS_SHARED);  /* Allocate memory to pmutex here. */  /* Initialise mutex. */ pthread_mutex_init(pmutex, &attrmutex);  /* Use the mutex. */  /* Clean up. */ pthread_mutex_destroy(pmutex); pthread_mutexattr_destroy(&attrmutex);  

(error checking left out for the sake of this example's readability)

The same applies to a condition variable which should be shared between processes: http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_condattr_setpshared.html

#include <pthread.h>  ...  pthread_cond_t * pcond = NULL; pthread_condattr_t attrcond;  /* Initialise attribute to condition. */ pthread_condattr_init(&attrcond); pthread_condattr_setpshared(&attrcond, PTHREAD_PROCESS_SHARED);  /* Allocate memory to pcond here. */  /* Initialise condition. */ pthread_cond_init(pcond, &attrcond);  /* Use the condition. */  /* Clean up. */ pthread_cond_destroy(pcond); pthread_condattr_destroy(&attrcond);  

(error checking left out for the sake of this example's readability)


Also see this answer: https://stackoverflow.com/a/2390670/694576

like image 153
alk Avatar answered Sep 29 '22 14:09

alk


Waiting for a condition should be preceded by a while statement, like this:

pthread_mutex_lock(mutex); while(!conditionSatisfied)     pthread_cond_wait(condition, mutex); pthread_mutex_unlock(mutex); 

while signaling should be done in the following way:

pthread_mutex_lock(mutex); conditionSatisfied = true; pthread_cond_signal(condition); pthread_mutex_unlock(mutex); 
like image 32
HAL9000 Avatar answered Sep 29 '22 14:09

HAL9000