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

求助:如何用两个互斥锁同步生产者消费者?环形缓冲区线程安全实现

线程安全环形缓冲区同步优化方案

问题根源分析

你的代码被ThreadSanitizer检测到数据竞争,核心原因是:

  • 共享数据未被统一保护:缓冲区的read、write指针是所有生产者、消费者的共享状态,但生产者仅持有mutex_write,消费者仅持有mutex_read,导致读写线程可同时访问/修改这些指针,触发竞争。
  • 条件变量使用不规范:调用pthread_cond_timedwait前未循环检查等待条件,易出现虚假唤醒;超时时间在锁外计算存在时间窗口误差。
  • 语法错误:return retval中retval未定义,注释符号不完整。

修正后的代码

基于给定的rbuf结构体,调整同步逻辑如下(使用单一互斥锁保护所有共享状态,利用原有条件变量实现读写同步):

/*
typedef struct {
    uint8_t* read;
    uint8_t* write;
    uint8_t* begin;
    uint8_t* end;
    pthread_mutex_t mutex_read;
    pthread_mutex_t mutex_write;
    pthread_cond_t signal_read;
    pthread_cond_t signal_write;
} rbuf;
*/

int producer(rbuf *buffer, void *message, size_t message_len) {
    int val;
    struct timespec to;

    while (1) {
        // 持有全局锁,保护所有缓冲区共享状态的访问
        pthread_mutex_lock(&buffer->mutex_write);
        
        // 锁内计算超时时间,避免时间窗口问题
        clock_gettime(CLOCK_REALTIME, &to);
        to.tv_sec += 1;

        val = write(buffer, message, message_len);
        if (val == 1) { // 写入成功
            // 通知等待的读线程有新数据
            pthread_cond_signal(&buffer->signal_read);
            pthread_mutex_unlock(&buffer->mutex_write);
            return val;
        }

        // 缓冲区满,等待读线程释放空间(带超时)
        if (pthread_cond_timedwait(&buffer->signal_write, &buffer->mutex_write, &to) == ETIMEDOUT) {
            pthread_mutex_unlock(&buffer->mutex_write);
            return val; // 返回写入失败状态
        }

        // 非超时唤醒,释放锁后循环重试
        pthread_mutex_unlock(&buffer->mutex_write);
    }
}

int consumer(rbuf *buffer, void *buffer_read, size_t *buffer_len) {
    int val;
    struct timespec to;

    while (1) {
        // 持有同一全局锁,保证读写互斥
        pthread_mutex_lock(&buffer->mutex_write);
        
        clock_gettime(CLOCK_REALTIME, &to);
        to.tv_sec += 1;

        val = read(buffer, buffer_read, buffer_len);
        if (val == 1) { // 读取成功
            // 通知等待的写线程有空闲空间
            pthread_cond_signal(&buffer->signal_write);
            pthread_mutex_unlock(&buffer->mutex_write);
            return val;
        }

        // 缓冲区空,等待写线程写入数据(带超时)
        if (pthread_cond_timedwait(&buffer->signal_read, &buffer->mutex_write, &to) == ETIMEDOUT) {
            pthread_mutex_unlock(&buffer->mutex_write);
            return val; // 返回读取失败状态
        }

        // 非超时唤醒,释放锁后循环重试
        pthread_mutex_unlock(&buffer->mutex_write);
    }
}

关键优化点说明

  • 统一共享状态保护:所有访问read、write指针及缓冲区空/满判断的操作,都在mutex_write的临界区内执行,彻底消除跨线程数据竞争。
  • 规范条件变量使用:通过外层循环保证pthread_cond_timedwait返回后重新检查缓冲区状态,避免虚假唤醒导致的逻辑错误。
  • 精准超时控制:在锁内获取当前时间并计算超时,确保超时时间的准确性,避免锁外计算带来的时间偏差。
  • 语法错误修复:替换未定义的retval为正确的返回值val,修正注释格式问题。

关于多余mutex的说明

给定结构体中的mutex_read未在上述代码中使用,若需利用该锁,可将其用于消费者线程内部的局部资源互斥(如消费者自身的缓存处理),但缓冲区共享状态的保护必须依赖单一全局锁,否则仍会引发数据竞争。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 12:35:25