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

是否应对共享资源的状态检查执行原子操作?以有界缓冲区问题为例

共享资源状态检查的原子性问题——以有界缓冲区为例

我想了解是否应对共享资源的状态检查执行原子操作。例如,考虑以下展示经典Bounded-Buffer问题的代码:

lock buf_lock = <initially unlocked>
condition producer_CV = <initially empty>
condition consumer_CV = <initially empty>

Producer(item) {
    acquire(&buf_lock);
    while (buffer full) { 
        cond_wait(&producer_CV, &buf_lock); 
    }
    enqueue(item);
    cond_signal(&consumer_CV);
    release(&buf_lock);
}

Consumer() {
    acquire(buf_lock);
    while (buffer empty) { 
        cond_wait(&consumer_CV, &buf_lock); 
    }
    item = dequeue();
    cond_signal(&producer_CV);
    release(buf_lock);
    return item;
}

我特别想知道while循环中的“buffer full”或“buffer empty”语句的求值与检查是否为原子操作。

我的猜想:我认为应该执行原子检查,反证如下场景:

  • 队列中仅存在一个元素
  • 某个Consumer线程已被唤醒并获取了锁,准备从队列中取出元素时被抢占退出CPU。此时若另一个Consumer线程在未获取锁的情况下检查队列非空(假设检查非原子),则会尝试取出元素,显然会引发冲突……

问题解答

你的猜想完全正确,共享资源的状态检查必须是原子操作,否则必然会引发线程安全问题。

在你给出的有界缓冲区代码中,buffer full和buffer empty的检查之所以安全,核心原因是这些检查是在持有buf_lock锁的前提下执行的——锁本身就保证了这段检查操作的原子性:同一时间只有一个线程能持有锁,也就只有一个线程能执行缓冲区状态的检查、后续的入队/出队操作。

你假设的场景恰好能说明非原子检查的危害:如果第二个Consumer线程可以在不持有锁的情况下检查缓冲区状态,它会看到缓冲区非空,接着尝试获取锁执行出队,但此时第一个Consumer线程只是被抢占,它仍然持有锁(或恢复后会继续持有锁执行出队),最终两个线程都会尝试对同一个元素执行出队操作,导致数据丢失、缓冲区状态混乱等严重问题。

另外需要注意,代码里用while而非if来检查状态,也是为了应对虚假唤醒的情况——即使线程被唤醒,它也必须重新原子性地检查缓冲区状态,因为可能在它被唤醒到获取锁的这段时间里,其他线程已经修改了缓冲区的状态,只有重新持有锁检查才能确保当前状态的准确性。


内容的提问来源于stack exchange,提问作者Vacation Due 20000

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 12:50:01