【问题标题】:Pthread Condition Variables not Signalling even though set to PTHREAD_PROCESS_SHARED即使设置为 PTHREAD_PROCESS_SHARED,Pthread 条件变量也不会发出信号
【发布时间】:2016-05-28 16:37:46
【问题描述】:

我在跨文件使用条件变量和互斥体时遇到了共享内存问题。

我的研究把我带到了这里Share condition variable & mutex between processes: does mutex have to locked before? 如果您运行两个完全独立的可执行文件,则 OP 发布的解决方案将不起作用。我尝试了他的方法来解决我自己的问题,两个单独的进程只是不会互相发出信号。因此,为了确认 OPs 代码确实有效,如下所示,我复制了他的代码并在中途添加了一个#define,以便您可以编译并作为父亲启动,更改定义并作为儿子启动。 如果您像 OP 一样只用一个 fork 运行代码,它就可以工作。如果你作为两个单独的可执行文件运行,它就不起作用...... 有人有什么想法吗?

背景问题 这开始于我之前的问题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();
}

【问题讨论】:

    标签: c++ linux qt pthreads


    【解决方案1】:

    您在子进程中不必要地截断了互斥锁和条件变量的共享内存。由于这部分曾经发生在原始代码中的 fork() 之前,因此您只为这对夫妇执行了一次。但是在两个单独的进程中,您分别在父进程中使用跨进程 pthread 互斥锁和条件变量初始化共享内存,然后在子进程中使用 O_TRUNC 销毁 pthreads 放入的所有内容。正确的代码如下:

    父亲.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);
    }
    

    儿子.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!!!!!!!!
    $
    

    【讨论】:

    • 非常感谢@ALGOholic,我没看到。所以我看到子进程也不需要 shm_open 之后的 ftruncate。那么这意味着 fttruncate 是在共享内存本身上运行,而不是调整各个进程的虚拟地址空间以匹配?
    • 我看待它的方式 - shm_open() 返回一个“文件”句柄,因此在逻辑上它应该表现为 +- 作为文件。 ftruncate() 只是设置“文件”大小——与进程的虚拟内存无关。后一部分由 mmap() 调用处理,您可以在其中指定内存大小并在虚拟内存页面与其后备存储(shm“文件”)之间建立链接。在幕后,内核识别两个 mmap() 调用的公共后备存储,并将相同的 VM 页面分配给两个进程。简短的回答是 - 是的,ftruncate() 对“shm”文件进行操作,并且在儿子中不是必需的。
    • 完美的代码,我一直在尝试解决这个问题。没有任何文档清楚说明如何在共享内存上下文中执行此操作。有没有办法用单个内存映射文件而不是 2 来做到这一点
    猜你喜欢
    • 2019-09-18
    • 2016-02-01
    • 1970-01-01
    • 2021-04-26
    • 2012-07-04
    • 2018-02-07
    • 2011-07-07
    • 1970-01-01
    • 2015-03-21
    相关资源
    最近更新 更多