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

Linux下C++进程同步:生产者消费者场景的二元信号量需求

Linux下C++实现生产者消费者的二元信号量同步方案

针对你需要的仅传递存在新数据信号、不递增计数的二元同步机制,在Linux下有两种高效的实现方式,完全适配你的共享内存循环缓冲区场景:


1. 使用Futex用户态同步原语

Futex是Linux内核提供的轻量级同步原语,能直接实现你需要的"置1通知、无计数"逻辑,无需内核态频繁切换,性能最优。

核心逻辑

  • 共享内存中维护一个volatile int类型的信号标记,初始为0
  • 生产者:将标记设为1,调用futex_wake唤醒等待的消费者
  • 消费者:循环检查标记,若为0则调用futex_wait休眠;若为1则处理数据,处理完成后将标记重置为0

代码示例

#include <linux/futex.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <sys/mman.h>
#include <fcntl.h>

// 封装futex系统调用
int futex(int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3) {
    return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
}

// 共享内存结构
struct SharedData {
    volatile int has_new_data; // 二元信号标记:0=无新数据,1=有新数据
    char buffer[1024]; // 你的循环缓冲区
};

int main(int argc, char *argv[]) {
    const char *shm_name = "/my_shared_memory";
    int shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, 0666);
    ftruncate(shm_fd, sizeof(SharedData));
    SharedData *shared = static_cast<SharedData*>(mmap(nullptr, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0));

    if (argc == 1) {
        // 生产者进程
        while (true) {
            // 生产数据到缓冲区
            strcpy(shared->buffer, "New data from producer");
            // 设置信号为1并唤醒消费者
            shared->has_new_data = 1;
            futex(const_cast<int*>(&shared->has_new_data), FUTEX_WAKE, 1, nullptr, nullptr, 0);
            sleep(2); // 模拟生产间隔
        }
    } else {
        // 消费者进程
        while (true) {
            // 等待新数据信号
            while (shared->has_new_data == 0) {
                futex(const_cast<int*>(&shared->has_new_data), FUTEX_WAIT, 0, nullptr, nullptr, 0);
            }
            // 处理数据
            std::cout << "Consumer got data: " << shared->buffer << std::endl;
            // 重置信号为0
            shared->has_new_data = 0;
        }
    }

    munmap(shared, sizeof(SharedData));
    shm_unlink(shm_name);
    return 0;
}

编译命令:g++ -o prod_cons prod_cons.cpp -lrt


2. 使用eventfd(文件描述符式通知)

eventfd是Linux提供的基于文件描述符的同步机制,你可以通过手动重置计数来避免递增,实现二元信号的逻辑。

核心逻辑

  • 创建eventfd初始值设为0
  • 生产者:先读取当前值(清零),再写入1,确保信号始终是1(不管之前状态)
  • 消费者:读取eventfd的值,若返回大于0则处理数据,读取后eventfd自动清零

代码示例

#include <sys/eventfd.h>
#include <unistd.h>
#include <cstdint>
#include <iostream>
#include <sys/mman.h>
#include <fcntl.h>
#include <cstring>

// 共享内存结构
struct SharedData {
    char buffer[1024]; // 你的循环缓冲区
};

int main(int argc, char *argv[]) {
    const char *shm_name = "/my_shared_memory";
    int shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, 0666);
    ftruncate(shm_fd, sizeof(SharedData));
    SharedData *shared = static_cast<SharedData*>(mmap(nullptr, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0));

    // 创建eventfd
    int efd = eventfd(0, 0);

    if (argc == 1) {
        // 生产者进程
        while (true) {
            // 生产数据到缓冲区
            strcpy(shared->buffer, "New data from producer");
            // 先清零,再写入1(确保信号是1,不累积)
            eventfd_t val;
            eventfd_read(efd, &val);
            eventfd_write(efd, 1);
            sleep(2); // 模拟生产间隔
        }
    } else {
        // 消费者进程
        while (true) {
            eventfd_t val;
            // 阻塞等待信号
            eventfd_read(efd, &val);
            // 处理数据
            std::cout << "Consumer got data: " << shared->buffer << std::endl;
        }
    }

    munmap(shared, sizeof(SharedData));
    shm_unlink(shm_name);
    close(efd);
    return 0;
}

编译命令:g++ -o prod_cons_event prod_cons_event.cpp -lrt


方案对比

  • Futex:性能最高,完全基于用户态+内核态唤醒,适合对延迟敏感的场景
  • eventfd:使用文件描述符,可与select/poll/epoll结合,适合需要多路复用的场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 20:05:13