多线程TIC/TAC交替输出异常:Mutex同步问题求助
修复TIC-TAC线程同步异常并实现交替输出
错误原因分析
你遇到的System.ApplicationException(对象同步方法从非同步代码块调用),核心原因是Mutex的所有权规则:只有通过WaitOne()获取到Mutex所有权的线程,才能调用ReleaseMutex()释放它。你的代码存在两处违反规则的情况:
- 初始化
mutexTIC时传入true,意味着创建Class1实例的主线程直接拥有了mutexTIC的所有权,但后续是TAC线程尝试调用mutexTIC.ReleaseMutex(),完全不具备所有权。 - 多个TIC/TAC线程交叉操作Mutex,导致所有权混乱,比如TIC线程释放
mutexTAC,但mutexTAC可能被其他TAC线程持有,同样触发异常。
解决方案:用AutoResetEvent实现交替同步
AutoResetEvent天生适合这种"交替唤醒"的场景,它会在调用Set()后自动重置为非信号状态,刚好匹配TIC-TAC的执行逻辑:
public class Class1 { // 初始允许TIC执行,TAC线程等待 private readonly AutoResetEvent _ticSignal = new AutoResetEvent(true); private readonly AutoResetEvent _tacSignal = new AutoResetEvent(false); // 记录已输出的TIC次数,控制总交替次数(3次) private int _ticExecutedCount; private readonly object _countLock = new object(); public void TIC() { _ticSignal.WaitOne(); lock (_countLock) { // 已完成3次TIC则直接唤醒TAC线程并退出 if (_ticExecutedCount >= 3) { _tacSignal.Set(); return; } Console.Write("TIC "); _ticExecutedCount++; } // 唤醒TAC线程执行 _tacSignal.Set(); } public void TAC() { _tacSignal.WaitOne(); lock (_countLock) { // 无有效TIC输出则直接唤醒TIC线程并退出 if (_ticExecutedCount == 0 || _ticExecutedCount > 3) { _ticSignal.Set(); return; } Console.Write("TAC "); } // 唤醒下一个TIC线程执行 _ticSignal.Set(); } }
另一种方案:用Monitor+状态标记实现
如果不想用Event类,也可以用.NET内置的Monitor结合状态变量实现线程同步,逻辑更直观:
public class Class1 { private readonly object _syncLock = new object(); // 标记当前是否轮到TIC输出 private bool _isTicTurn = true; // 记录已完成的TIC-TAC配对数 private int _completedPairs; public void TIC() { lock (_syncLock) { // 等待轮到自己,或已完成3次配对则退出 while (!_isTicTurn && _completedPairs < 3) { Monitor.Wait(_syncLock); } if (_completedPairs >= 3) return; Console.Write("TIC "); _isTicTurn = false; _completedPairs++; // 唤醒所有等待的线程,通知状态变更 Monitor.PulseAll(_syncLock); } } public void TAC() { lock (_syncLock) { // 等待轮到自己,或已完成配对则退出 while (_isTicTurn && _completedPairs < 3) { Monitor.Wait(_syncLock); } if (_completedPairs > 3) return; Console.Write("TAC "); _isTicTurn = true; Monitor.PulseAll(_syncLock); } } }
验证效果
保持你原来的线程创建和启动代码不变,运行后会稳定输出:TIC TAC TIC TAC TIC TAC
内容的提问来源于stack exchange,提问作者Yurii Salyha
相关产品推荐
相关产品推荐

