C#信号量同步报错:非同步代码块调用同步方法求解决方案
解决C#中跨线程调用
ReleaseMutex()引发的错误:信号量与Mutex的误用 看起来你是把伪代码里的**信号量(Semaphore)**错误地用成了Mutex,这才导致了跨线程调用ReleaseMutex()的问题——毕竟Mutex的核心规则就是:只有调用过WaitOne()获取到它的线程,才能调用ReleaseMutex()释放它,而伪代码的逻辑根本不满足这个约束。
问题根源拆解
伪代码里的cust_ready是一个信号量,用来实现「生产者通知消费者有新任务」的同步逻辑:
- Thread1(生产者)生产完成后,通过
signal(cust_ready)告诉消费者「有新顾客了」 - Thread2(消费者)通过
wait(cust_ready)等待生产者的通知
但你在C#里把cust_ready声明成了Mutex,这就完全搞错了同步原语的类型——Mutex是互斥锁,用来保护临界区资源,不是用来做线程间通知的信号量。
修正后的C#代码实现
我们需要把cust_ready换成SemaphoreSlim(C#里轻量级的信号量实现),同时严格贴合原伪代码的逻辑结构:
首先定义类级别的同步原语和队列:
// 保护队列的互斥锁,对应伪代码的mutex2 private static readonly Mutex mutex2 = new Mutex(); // 信号量,初始计数为0(一开始没有顾客,消费者需要等待),对应伪代码的cust_ready private static readonly SemaphoreSlim cust_ready = new SemaphoreSlim(0); // 存储顾客的队列 private static readonly Queue<int> customerQueue = new Queue<int>();
然后是Thread1的生产者逻辑:
// Thread1 代码 mutex2.WaitOne(); // 进入临界区,保护队列的入队操作 customerQueue.Enqueue(custnr); mutex2.ReleaseMutex(); // 离开临界区 cust_ready.Release(); // 发送信号:有新顾客了,对应伪代码的signal(cust_ready)
Thread2的消费者逻辑:
// Thread2 代码 cust_ready.Wait(); // 等待生产者的信号,对应伪代码的wait(cust_ready) mutex2.WaitOne(); // 进入临界区,保护队列的出队操作 customerQueue.TryDequeue(out var b_cust); mutex2.ReleaseMutex(); // 离开临界区
额外优化说明
如果改用ConcurrentQueue<int>替代普通Queue<int>,因为它本身是线程安全的,你可以直接去掉mutex2,简化代码:
private static readonly SemaphoreSlim cust_ready = new SemaphoreSlim(0); private static readonly ConcurrentQueue<int> customerQueue = new ConcurrentQueue<int>(); // Thread1 代码 customerQueue.Enqueue(custnr); cust_ready.Release(); // Thread2 代码 cust_ready.Wait(); customerQueue.TryDequeue(out var b_cust);
这种写法更符合C#的现代线程安全实践,同时完美匹配伪代码的核心逻辑。
另外要记住:SemaphoreSlim.Release()不需要调用线程之前调用过Wait(),它只是单纯增加信号量的计数,正好匹配伪代码里signal的语义——生产者只需要通知消费者,不需要「持有」这个信号量。
内容的提问来源于stack exchange,提问作者SOfanatic
相关产品推荐
相关产品推荐

