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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:32:34