C语言 在进程之间共享条件变量和互斥锁:互斥锁之前是否必须锁定?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20325146/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 10:25:21  来源:igfitidea点击:

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

cpthreadsipcmutexcondition-variable

提问by SagittariusA

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

我需要一些帮助来理解如何在 C 中使用条件变量来解决练习。这是一个小例子:

#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_openand 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?

问题是进程的父亲继续被锁定,即使在儿子发出信号之后。一切都在共享内存中(使用shm_openmmap),因此两个进程的条件应该相同。在调用wait或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;

}

回答by alk

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

要在进程之间共享,需要通过正确初始化的属性相应地初始化互斥锁: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

这同样适用于应该在进程之间共享的条件变量: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

另请参阅此答案:https: //stackoverflow.com/a/2390670/694576

回答by HAL9000

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

等待条件之前应该有一个 while 语句,如下所示:

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);

回答by UmNyobe

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...

是的,互斥锁必须在 之前锁定pthread_cond_wait,但不必为pthread_cond_signal。如果你回头看看你的代码,你会看到互斥锁会被解锁两次,这是一个错误的迹象......孩子也有可能在一个被父级销毁的互斥锁上调用解锁......

Btw sleeping doesn't guarantee that the parent will execute first. To ensure this you will need ... a condition variable...

顺便说一句,睡眠并不能保证父母会先执行。为了确保这一点,你需要......一个条件变量......