Mutex不是线程锁,单进程内用性能差十倍且易漏释放、跨线程释放;跨进程需命名并区分Local(会话级)与Global(系统级)前缀,注意大小写与转义;必须try/finally配ReleaseMutex,不可跨线程释放;AbandonedMutexException需校验资源一致性;单进程同步应优先用lock。

Mutex不是线程锁,别在单进程里当lock用——性能差十倍,还容易漏释放、跨线程释放、误判状态。
命名Mutex才能跨进程,Local和Global前缀不能混用
无参构造 new Mutex() 或带 false 的 new Mutex(false) 创建的是匿名互斥体,只在当前进程内有效,其他进程根本看不到它。真要跨进程,必须传名称,且注意作用域前缀:
-
"Local\myapp-config-writer":默认用户会话(Session)内所有进程可见,桌面应用首选 -
"Global\myapp-config-writer":全系统可见,但普通用户进程创建时会抛UnauthorizedAccessException,除非服务以LocalSystem运行并配置 DACL - 名称区分大小写,建议全小写 + 连字符,避免空格、纯数字开头或特殊字符
- 双反斜杠
\是 C# 字符串转义要求,不是路径风格,写成"Localmyapp"会编译报错
WaitOne 后必须 try/finally 调用 ReleaseMutex,且只能同线程释放
Mutex 没有 using 语法糖自动释放,Dispose() 或 Close() 不等于释放所有权。忘记 ReleaseMutex(),等于给其他进程设永久路障;跨线程调用则直接抛 ApplicationException(错误信息是 “Object synchronization method was called from an unsynchronized block of code”):
- 临界区逻辑必须包在
try块里,ReleaseMutex()必须放在对应finally中 - 不要在
catch块里盲目调用ReleaseMutex()—— 异常发生时你未必持有锁 - 若临界区可能抛异常又不想在
finally里重复判断,可用bool hasOwnership = mutex.WaitOne(),再配if (hasOwnership) mutex.ReleaseMutex(); -
WaitOne(0)是非阻塞试探,适合轮询;WaitOne(Timeout.Infinite)会永久挂起,生产环境慎用
AbandonedMutexException 比超时更危险,必须校验资源一致性
WaitOne 返回 false 只代表超时,真正要警惕的是 AbandonedMutexException:它说明上一个持有锁的进程崩溃或没调 ReleaseMutex(),临界区资源极可能已损坏。
- 捕获该异常后,当前线程会自动获得所有权,但你不能直接继续操作
- 必须手动校验共享状态:比如读取文件后验证 JSON 格式、比对 CRC、重载缓存、检查数据库事务标记
- 别依赖
out createdNew参数判断“谁先抢到锁”——它只表示内核对象是否新建,不反映当前线程是否获得所有权 - 防多开场景下,别用
Process.GetProcessesByName(),那是竞态条件温床;应启动时立刻WaitOne命名Mutex,超时即退出
最易被忽略的一点:Mutex 的开销来自每次 WaitOne 都触发用户态→内核态切换,而 lock(obj) 是纯用户态操作。单进程同步选 lock 不仅更快,而且不会因忘记释放或跨线程释放导致死锁或崩溃。


















