2016-02-17 92 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