问题
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;
}
回答1:
To be sharable 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
回答2:
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);
回答3:
yes, mutex have to be locked before pthread_cond_wait
, but doesn't have to for pthread_cond_signal
. If you look back at your code, you see that the mutex will be unlocked twice, which is a sign of error... it is also possible for the child to call unlock on a mutex which has been destroyed by the parent...
Btw sleeping doesn't guarantee that the parent will execute first. To ensure this you will need ... a condition variable...
来源:https://stackoverflow.com/questions/20325146/share-condition-variable-mutex-between-processes-does-mutex-have-to-locked-be