You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

进程共享pthread_cond_t在gcc 8.4失效 gcc 4.8.5运行正常问题求助

问题描述

近期将操作系统从RHEL 7.6(搭载gcc 4.8.5)升级到RHEL 8.4(搭载gcc 8.4)后,基于pthread_mutex_t和pthread_cond_t实现的跨进程同步逻辑出现异常。未使用C++标准库的std::mutex和std::condition_variable是因为这两个类不支持跨进程同步。该逻辑在gcc 4.8.5环境下运行正常,升级到gcc 8.4后失效。

复现步骤
  • 先启动First_Process进程
  • 再启动Second_Process进程
  • 用Ctrl+C强制终止Second_Process进程
  • 重新运行Second_Process进程,此时两个进程都不再有终端输出
相关代码

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;
    }
}
问题原因

该问题本质不是gcc版本差异导致,而是RHEL 8对应的glibc版本升级后,进程共享同步原语、健壮互斥量的逻辑校验更严格,旧代码的未定义行为在旧版glibc下偶然可用,新版环境下问题暴露:

  1. 析构函数逻辑错误:所有使用共享内存的进程退出时都会调用shm_unlink删除共享内存名,导致后续新启动的进程无法找到共享内存对象。
  2. 未显式初始化共享内存中的flag标志:仅依赖ftruncate对共享内存的清零行为,未显式赋值初始值,存在未定义行为风险。
  3. 缺失完整的错误处理逻辑:健壮互斥量返回ENOTRECOVERABLE等错误时未做处理,直接操作互斥量会导致流程卡住。
  4. 条件变量未显式指定时钟属性:不同glibc版本对进程共享条件变量的默认时钟设置存在差异,可能导致条件等待逻辑异常。
修复方案
  1. 修正析构函数逻辑,仅共享内存的创建者有权限执行shm_unlink:
Binary_Semaphore::~Binary_Semaphore() {
    if (is_to_be_created) {
        pthread_mutex_destroy(&bin_sem_attr->mutex);
        pthread_cond_destroy(&bin_sem_attr->cvar);
        // 仅创建者删除共享内存名
        shm_unlink(bin_sem_attr_shm_ID.c_str());
    }
    if (is_process_shared) {
        munmap(bin_sem_attr, sizeof(binary_semaphore_attr));
    }
}
  1. 创建共享内存时显式初始化flag标志,在构造函数初始化完互斥量和条件变量后添加:
bin_sem_attr->flag = false;
  1. 完善健壮互斥量的错误处理,对pthread_mutex_lock返回的所有错误做分支处理,遇到ENOTRECOVERABLE错误时重新初始化同步原语,避免流程卡住。
  2. 显式指定条件变量的时钟属性,初始化条件变量属性时添加:
pthread_condattr_setclock(&cvar_attr, CLOCK_MONOTONIC);

内容的提问来源于stack exchange,提问作者Harry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 03:24:03