2016-02-17 51 views
0

我在使用条件变量和互斥文件跨文件共享内存时遇到问题。即使设置为PTHREAD_PROCESS_SHARED Pthread条件变量不发送信号

我的研究导致我到这里Share condition variable & mutex between processes: does mutex have to locked before? 如果您运行两个完全独立的可执行文件,OP发布的解决方案不起作用。我尝试了他自己的方法来解决我自己的问题,而且两个独立的过程不会互相传递信号。因此,为了确认OP代码实际上起作用,如下所示,我复制了他的代码,并在中途添加了一个#define,以便您可以编译并作为父亲启动,更改定义并作为儿子启动。 如果您使用OP运行代码,只用叉子,它就可以工作。如果您以两个独立的可执行文件运行,则不起作用...... 有没有人有任何想法?

背景问题 这个开始与我先前的问题POSIX Shared Memory Sync Across Processes C++/C++11

测试代码

#include <QCoreApplication> 

#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[]) 
{ 
    QCoreApplication a(argc, 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); 
    } 

//#define father 
#ifdef father 


    /* HERE WE GO */ 
    /**************************************/ 

     /* set mutex shared between processes */ 
    pthread_mutexattr_t mutexAttr; 
    pthread_mutexattr_init(&mutexAttr); 
    pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED); 
    pthread_mutex_init(mutex, &mutexAttr); 

    /* set condition shared between processes */ 
    pthread_condattr_t condAttr; 
    pthread_condattr_init(&condAttr); 
    pthread_condattr_setpshared(&condAttr, PTHREAD_PROCESS_SHARED); 
    pthread_cond_init(condition, &condAttr); 

    /*************************************/ 


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

// if (!fork()) { 

//  sleep(3); 

     pthread_mutex_lock(mutex); 
     pthread_cond_signal(condition); 
     printf("son signaled\n"); 
     pthread_mutex_unlock(mutex); 
     exit(0); 
// } 

// else { 

#endif 

// } 

    exit(0); 

    return a.exec(); 
} 

回答

1

你截断互斥量和条件变量的共享内存不必要的子进程。由于这部分过去是在原始代码的fork()之前发生的,所以你只为这对夫妇做过一次。但是在两个独立的进程中,你需要在父进程中分别使用跨进程pthread互斥和条件变量来初始化共享内存,然后通过在子中使用O_TRUNC来销毁pthreads放入的所有内容。正确的代码如下:

father.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 "/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_init(&mutexAttr); 
    pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED); 
    pthread_mutex_init(mutex, &mutexAttr); 

    /* set condition shared between processes */ 
    pthread_condattr_t condAttr; 
    pthread_condattr_init(&condAttr); 
    pthread_condattr_setpshared(&condAttr, PTHREAD_PROCESS_SHARED); 
    pthread_cond_init(condition, &condAttr); 

    /*************************************/ 


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

    exit(0); 
} 

son.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 "/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, mode); 

    if (des_mutex < 0) { 
     perror("failure on shm_open on des_mutex"); 
     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, mode); 

    if (des_cond < 0) { 
     perror("failure on shm_open on des_cond"); 
     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_mutex_lock(mutex); 
    pthread_cond_signal(condition); 
    printf("son signaled\n"); 
    pthread_mutex_unlock(mutex); 
    exit(0); 
} 

测试:

1st terminal: $ ./father 
father waits on condition 

2nd terminal: $ ./son 
son signaled 

1st terminal: Signaled by son process, wake up!!!!!!!! 
$ 
+0

谢谢你这么多@ALGOholic,我没有看到那。所以我看到shm_open之后的子过程不需要ftruncate。那么这意味着fttruncate在共享内存本身上运行,而不是确定单个进程虚拟地址空间的匹配大小? – Asvaldr

+0

我看着它的方式 - shm_open()返回一个“文件”句柄,因此在逻辑上它应该表现为+ - 作为文件。 ftruncate()简单地设置“文件”大小 - 与进程的虚拟内存无关。后一部分由mmap()调用处理,您可以在其中指定内存大小,并在虚拟内存页面与其后备存储(shm“文件”)之间建立链接。在幕后,内核为mmap()调用识别共同的后备存储,并为这两个进程分配相同的VM页面。简短的回答是 - 是的,ftruncate()在“shm”文件上运行,在儿子中不是必需的。 – ALGOholic