识别以下基于Monitor实现的Semaphore代码中的缺陷
自定义Semaphore实现的缺陷分析
先看给出的自定义信号量实现代码:
public class MySemaphore { private object _mutex = new object(); private int _currAvail; public MySemaphore(int capacity) { _currAvail = capacity; } public void Wait() { lock (_mutex) { if (_currAvail == 0) Monitor.Wait(_mutex); _currAvail--; } } public void Signal() { lock (_mutex) { _currAvail++; Monitor.Pulse(_mutex); } } }
核心缺陷
虚假唤醒导致许可过度消耗:
Wait方法中用if (_currAvail == 0)判断是否等待是错误的。Monitor.Wait可能被虚假唤醒(即使未调用Pulse/PulseAll,线程也可能被唤醒),或者当一个线程被Pulse唤醒后,另一个线程可能先获取锁并消耗了刚释放的许可,此时当前线程的_currAvail已回到0,但代码会直接执行_currAvail--,导致_currAvail变成负数,信号量许可被非法超额占用。正确做法是用while循环持续检查条件:while (_currAvail == 0) Monitor.Wait(_mutex);缺少参数合法性校验:构造函数未对
capacity参数做校验,如果传入负数,_currAvail初始值为负,会导致Wait方法一开始就允许线程无限制消耗许可,完全违背信号量的设计意图。应该在构造函数中添加校验:if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity), "信号量容量不能为负数"); _currAvail = capacity;
次要问题
Signal方法唤醒策略的局限性:Monitor.Pulse只会唤醒等待队列中的一个线程,这本身符合信号量释放一个许可的逻辑,但如果存在多个线程等待,Pulse的唤醒机制无法保证公平性(无法确保等待最久的线程被优先唤醒),不过这属于实现细节层面的问题,不影响核心功能的正确性。
内容的提问来源于stack exchange,提问作者Ujjwal27
相关产品推荐
相关产品推荐

