c# 如何用 Mutex 实现跨进程同步

来源:这里教程网 时间:2026-02-21 17:40:52 作者:

为什么直接 new Mutex() 无法跨进程同步

因为

Mutex
默认是线程内可见的,不带名称的实例只在当前进程的线程间有效。跨进程必须用**命名互斥体**,且名称需全局唯一、符合 Windows 命名规则(如不能含反斜杠、长度限制等)。否则两个进程各自创建了同名但互不感知的
Mutex
,根本没锁住。

正确做法:使用带字符串名称的构造函数,例如
new Mutex(false, "MyApp_GlobalLock")
名称建议加前缀(如公司/应用名),避免与其他程序冲突 注意大小写敏感:Windows 上
"MyLock"
"mylock"
是两个不同互斥体

如何安全获取并释放命名 Mutex(含超时与异常处理)

跨进程场景下,

Mutex.WaitOne()
可能长时间阻塞(比如持有者崩溃未释放),必须设超时;同时要捕获
AbandonedMutexException
—— 这表示上一个持有者异常退出,系统已自动释放,但你需要重新初始化受保护资源。

bool acquired = false;
Mutex mutex = null;
try
{
    mutex = new Mutex(false, "MyApp_GlobalConfigAccess");
    acquired = mutex.WaitOne(3000); // 等待 3 秒
<pre class='brush:php;toolbar:false;'>if (!acquired)
{
    throw new TimeoutException("Failed to acquire global mutex within timeout.");
}
// ✅ 此时已获得跨进程独占访问权
UpdateSharedConfig();

} catch (AbandonedMutexException) { // 上一进程崩溃,Mutex 被系统释放,但数据可能处于不一致状态 // 必须先修复/重置共享状态,再继续 RepairSharedState(); UpdateSharedConfig(); } finally { if (acquired && mutex != null) { mutex.ReleaseMutex(); // ⚠️ 必须成对调用,否则其他进程永远等不到 } mutex?.Dispose(); }

为什么 ReleaseMutex() 报“Object synchronization method was called from an unsynchronized block of code”

这个错误(

System.ApplicationException
)说明你试图在**没真正获得所有权**的情况下调用
ReleaseMutex()
。常见原因:

WaitOne()
返回
false
(超时或被中断),但代码仍执行了
ReleaseMutex()
多个线程共用同一个
Mutex
实例,但只有其中一个线程成功 WaitOne,其他线程误调 Release
catch
块中未检查
acquired
就释放

解决关键是:只在

WaitOne()
明确返回
true
后才释放,且每个
WaitOne()
必须对应一次
ReleaseMutex()
—— 不能多也不能少。

跨网络或跨用户会话是否生效

默认的命名

Mutex
属于 **Local\** 命名空间,仅限同一用户会话(Session)内进程可见。如果目标进程运行在不同用户(如 Windows 服务跑在 SYSTEM 账户)、或远程桌面会话中,它根本看不到这个 Mutex。

需改用
"Global\MyApp_Lock"
前缀才能跨会话(要求管理员权限或 SeCreateGlobalPrivilege)
普通用户程序默认无权创建 Global\ 对象,会抛
UnauthorizedAccessException
更稳妥的做法是用
"Local\"
+ 用户 SID 组合命名,确保同用户下隔离,避免越权干扰

实际部署时,先确认进程运行上下文(交互式登录?服务?哪个用户?),再决定用

Local\
还是
Global\
,别想当然。

相关推荐