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

Mutex.TryOpenExisting()是否线程安全?为何代码中_mutex会出现null值?

Mutex.TryOpenExisting线程安全性及变量null问题解析

问题说明

在使用Mutex.TryOpenExisting()时,确认该方法的线程安全性,同时代码偶尔出现_mutex变量为null的错误,相关代码如下:

public class MutexNamedSystemDemo
{
    private const string _mutexName = @"Global\{C7F2DE44-8927-4B01-B8E1-D8F158A483A8}";
    private static Mutex _mutex;
    private static bool _intiallyOwned = false;
    private static int _count = 0;
    /*public MutexNamedSystemDemo()
     {
         _mutex = new Mutex(_intiallyOwned, _mutexName);
     }*/
 
     public void Main()
     {
         if (Mutex.TryOpenExisting(_mutexName, out _mutex) == false)
             _mutex = new Mutex(_intiallyOwned, _mutexName);
     }
}

核心解答

1. Mutex.TryOpenExisting的线程安全性

Mutex.TryOpenExisting()本身是线程安全的——它内部会正确处理系统级互斥体的并发访问,不会因多线程调用导致系统互斥体状态损坏。但这不代表你代码中对静态变量_mutex的访问是线程安全的。

2. _mutex为null的根本原因

问题出在静态变量_mutex的并发读写未加同步保护:

  • 当多个线程同时进入Main()方法时,可能出现以下时序:
    1. 线程A调用Mutex.TryOpenExisting()返回false,准备执行_mutex = new Mutex(...);
    2. 线程B同时调用Mutex.TryOpenExisting(),此时线程A还未完成互斥体实例化,因此也返回false,同样准备执行赋值;
    3. 极端情况下,线程调度可能导致赋值操作中断,或多线程赋值互相覆盖;更关键的是,无同步的静态变量读写无法保证内存可见性和原子性,部分线程可能读到未初始化的null。

3. 线程安全的修复方案

给静态变量_mutex的初始化逻辑加上同步锁,确保同一时间只有一个线程能完成初始化:

public class MutexNamedSystemDemo
{
    private const string _mutexName = @"Global\{C7F2DE44-8927-4B01-B8E1-D8F158A483A8}";
    private static Mutex _mutex;
    private static bool _intiallyOwned = false;
    private static int _count = 0;
    // 静态锁对象,用于同步初始化流程
    private static readonly object _initLock = new object();
 
    public void Main()
    {
        // 双重检查锁定模式,兼顾线程安全与性能
        if (_mutex == null)
        {
            lock (_initLock)
            {
                if (_mutex == null)
                {
                    if (!Mutex.TryOpenExisting(_mutexName, out _mutex))
                    {
                        _mutex = new Mutex(_intiallyOwned, _mutexName);
                    }
                }
            }
        }
    }
}
  • 双重检查锁定既避免了每次访问都加锁的性能损耗,又保证了初始化过程的线程安全;
  • .NET 2.0及以后版本中,lock语句会自动保证内存可见性,无需额外给_mutex添加volatile修饰符。

内容的提问来源于stack exchange,提问作者Alireza Molaei

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 17:50:57