【问题标题】:process shared pthread_cond_t doesn't work in gcc 8.4 but works in gcc 4.8.5进程共享 pthread_cond_t 在 gcc 8.4 中不起作用,但在 gcc 4.8.5 中起作用
【发布时间】:2021-12-07 13:25:59
【问题描述】:

最近我将我的操作系统从 RHEL 7.6(gcc 4.8.5) 升级到 RHEL 8.4(gcc 8.4),我遇到了与使用 pthread_mutex_tpthread_cond_t 进行进程同步相关的问题。我不使用 C++ std::mutexstd::condition_variable 的原因是它们不支持进程之间的同步。这曾经在gcc 4.8.5 中运行良好,但在gcc 8.4 中却不行。这是我的代码

Binary_Semaphore.h

#ifndef BINARY_SEMAPHORE_H
#define BINARY_SEMAPHORE_H

#include <iostream>
#include <string>
#include <cstdlib>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>

struct binary_semaphore_attr {
    pthread_mutex_t mutex;
    pthread_cond_t cvar;
    bool flag;
};

class Binary_Semaphore {

    struct binary_semaphore_attr *bin_sem_attr;
    const std::string bin_sem_attr_shm_ID;

    const bool is_process_shared;
    const bool is_to_be_created;

public:
    Binary_Semaphore(const std::string& bin_sem_attr_shm_ID, const bool is_process_shared, const bool is_to_be_created);
    ~Binary_Semaphore();
    
    void post();
    void wait();

    template<typename T>
    static void create_shared_memory(T **shm, const std::string& shm_ID, const bool is_to_be_created, const int o_flags, const int mode) {
        int shm_fd;
        if ((shm_fd = shm_open(shm_ID.c_str(), o_flags, mode)) == -1) {
            std::cerr << "shm_open failed with " << shm_ID << "\n";

            exit(EXIT_FAILURE);
        }

        if (is_to_be_created) {
            if (ftruncate(shm_fd, sizeof(T)) == -1) {
                std::cerr << "ftruncate failed with " << shm_ID << "\n";

                exit(EXIT_FAILURE);
            }
        }

        if ((*shm = reinterpret_cast<T*>(mmap(nullptr, sizeof(T), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0))) == MAP_FAILED) {
            std::cerr << "mmap failed with " << shm_ID << "\n";

            exit(EXIT_FAILURE);
        }

        close(shm_fd);
    }
};

#endif

Binary_Semaphore.cpp

#include "Binary_Semaphore.h"

Binary_Semaphore::Binary_Semaphore(const std::string& bin_sem_attr_shm_ID, const bool is_process_shared, const bool is_to_be_created) : bin_sem_attr_shm_ID(bin_sem_attr_shm_ID), is_process_shared(is_process_shared), is_to_be_created(is_to_be_created) {
    /* set binary semaphore attribute */
    if (is_to_be_created) {
        if (is_process_shared) {
            create_shared_memory(&bin_sem_attr, bin_sem_attr_shm_ID, is_to_be_created, O_CREAT | O_RDWR | O_TRUNC, S_IRWXU | S_IRWXG);

            /* set mutex shared between processes */
            pthread_mutexattr_t mutex_attr;
            pthread_mutexattr_init(&mutex_attr);
            pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
            pthread_mutexattr_setrobust(&mutex_attr, PTHREAD_MUTEX_ROBUST);
            pthread_mutex_init(&bin_sem_attr->mutex, &mutex_attr);
            pthread_mutexattr_destroy(&mutex_attr);

            /* set cvar shared between processes */
            pthread_condattr_t cvar_attr;
            pthread_condattr_init(&cvar_attr);
            pthread_condattr_setpshared(&cvar_attr, PTHREAD_PROCESS_SHARED);
            pthread_cond_init(&bin_sem_attr->cvar, &cvar_attr);
            pthread_condattr_destroy(&cvar_attr);
        } else
            bin_sem_attr = new binary_semaphore_attr();
    } else {
        if (is_process_shared)
            create_shared_memory(&bin_sem_attr, bin_sem_attr_shm_ID, is_to_be_created, O_RDWR, S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP);
    }
}

Binary_Semaphore::~Binary_Semaphore() {
    if (is_to_be_created) {
        pthread_mutex_destroy(&bin_sem_attr->mutex);
        pthread_cond_destroy(&bin_sem_attr->cvar);
    }

    if (is_process_shared) {
        munmap(bin_sem_attr, sizeof(binary_semaphore_attr));
        shm_unlink(bin_sem_attr_shm_ID.c_str());
    }
}

void Binary_Semaphore::post() {
    if (pthread_mutex_lock(&bin_sem_attr->mutex) == EOWNERDEAD)
        pthread_mutex_consistent(&bin_sem_attr->mutex);
    bin_sem_attr->flag = true;
    pthread_mutex_unlock(&bin_sem_attr->mutex);
    pthread_cond_signal(&bin_sem_attr->cvar);
}

void Binary_Semaphore::wait() {
    if (pthread_mutex_lock(&bin_sem_attr->mutex) == EOWNERDEAD)
        pthread_mutex_consistent(&bin_sem_attr->mutex);
    while (!bin_sem_attr->flag) {
        if (pthread_cond_wait(&bin_sem_attr->cvar, &bin_sem_attr->mutex) == EOWNERDEAD)
            pthread_mutex_consistent(&bin_sem_attr->mutex);
    }
    bin_sem_attr->flag = false;
    pthread_mutex_unlock(&bin_sem_attr->mutex);
}

First_Process.cpp

#include <iostream>
#include <string>
#include <chrono>
#include <thread>

#include "Binary_Semaphore.h"

int main() {
    static const std::string BSEM = R"(/BSEM)";
    
    Binary_Semaphore *binary_sem = new Binary_Semaphore(BSEM, true, true);
    while (true) {
        binary_sem->post();
        std::cout << "signal posted" << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1LL));
    }
}

Second_Process.cpp

#include <iostream>
#include <string>

#include "Binary_Semaphore.h"

int main() {
    static const std::string BSEM = R"(/BSEM)";
    
    Binary_Semaphore *binary_sem = new Binary_Semaphore(BSEM, true, false);
    while (true) {
        binary_sem->wait();
        std::cout << "signal received" << std::endl;
    }
}

运行第一个进程,然后运行第二个进程,然后使用 Ctrl^C 突然终止第二个进程,然后重新运行第二个进程,终端上不再打印(第一个进程和第二个进程)。

有人在使用最新的 gcc 版本时遇到过同样的问题吗?

【问题讨论】:

  • 无关:看起来你正在泄露你的binary_sems。程序将退出,操作系统将进行清理,但您不会感到知道析构函数已运行。
  • @KamilCuk 不,不应该。互斥锁保护flag
  • 如果在创建共享内存段时设置了O_EXCL会发生什么?以我的经验,“剩余的”共享同步对象在没有仔细清理的代码中引入了很大的错误空间。 (更不重要的是,你可以在mmap 后立即close() 那个 shm fd - 你不需要保留 fd。)
  • 所以我用代码 on gitlab 创建了一个仓库。它works on docker gcc:6fails with gcc:7
  • @KamilCuk 就像你说的glibc 的问题。您可以查看此链接sourceware.org/bugzilla/show_bug.cgi?id=21422。如果您有其他解决方案,请告诉我

标签: c++ gcc pthreads posix glibc


【解决方案1】:

glibc 不支持稳健的条件变量。 (它们不是 POSIX 的一部分。)如果参与进程之一异常终止,您需要使用条件变量重新创建共享内存段。

【讨论】:

  • 如果您有任何其他替代解决方案,请告诉我。
猜你喜欢
  • 2015-04-03
  • 2017-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多