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

如何在Unity Windows构建的应用中使用named mutex?有无可行方案

Unity Windows 构建使用命名Mutex的解决方案

问题根本原因

  • Unity编辑器运行时采用完整Mono运行时,原生支持.NET的System.Threading.Mutex类,包括命名Mutex的跨进程同步逻辑
  • Windows构建版本如果使用IL2CPP后端,.NET API兼容裁剪会限制命名Mutex的默认权限;同时打包后的应用默认运行在低权限上下文,无法访问全局命名空间的Mutex,部分Mono后端打包场景也会受安全配置限制出现兼容问题

可行解决方法

方法1:调整Mutex初始化参数,显式指定权限

这是改造成本最低的兼容方案,默认构造的命名Mutex会默认申请全局命名空间权限,打包后的应用无对应权限,修改为显式声明局部命名空间+自定义权限规则即可适配:

using System.Threading;
using System.Security.AccessControl;
using System.Security.Principal;

private Mutex _appMutex;
private bool _isNewInstance;

void Awake()
{
    // 配置允许所有用户访问的Mutex权限规则
    var mutexSecurity = new MutexSecurity();
    mutexSecurity.AddAccessRule(new MutexAccessRule(
        new SecurityIdentifier(WellKnownSidType.WorldSid, null),
        MutexRights.FullControl,
        AccessControlType.Allow));
    
    // 第二个参数为自定义Mutex名称,不要加"Global\"前缀,默认用"Local\"前缀即可适配打包后权限
    _appMutex = new Mutex(true, "YourAppUniquePrefix_MutexName", out _isNewInstance, mutexSecurity);
    
    if (!_isNewInstance)
    {
        // 已有实例运行时执行对应逻辑,比如单实例场景下直接退出
        Application.Quit();
        return;
    }
}

void OnDestroy()
{
    // 应用退出时必须主动释放Mutex句柄
    if (_appMutex != null)
    {
        _appMutex.ReleaseMutex();
        _appMutex.Dispose();
    }
}

注:如果用Mono后端打包,可直接省略权限参数运行,IL2CPP后端必须显式指定权限规则才能正常创建命名Mutex

方法2:调用Windows原生API创建Mutex

如果.NET封装的Mutex类仍然不生效,可以直接通过P/Invoke调用Windows系统原生CreateMutexW接口,完全绕过Unity运行时的API裁剪限制:

using System.Runtime.InteropServices;
using System;

public class Win32Mutex
{
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern IntPtr CreateMutexW(IntPtr lpMutexAttributes, bool bInitialOwner, string lpName);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool ReleaseMutex(IntPtr hMutex);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool CloseHandle(IntPtr hObject);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern uint GetLastError();
    
    private const uint ERROR_ALREADY_EXISTS = 183;
    
    private IntPtr _mutexHandle = IntPtr.Zero;
    public bool IsNewInstance { get; private set; }
    
    public Win32Mutex(string mutexName, bool initialOwner = true)
    {
        _mutexHandle = CreateMutexW(IntPtr.Zero, initialOwner, mutexName);
        uint errorCode = GetLastError();
        IsNewInstance = errorCode != ERROR_ALREADY_EXISTS;
    }
    
    public void Release()
    {
        if (_mutexHandle != IntPtr.Zero)
        {
            ReleaseMutex(_mutexHandle);
        }
    }
    
    public void Dispose()
    {
        if (_mutexHandle != IntPtr.Zero)
        {
            CloseHandle(_mutexHandle);
            _mutexHandle = IntPtr.Zero;
        }
    }
}

该实现IL2CPP/Mono后端完全兼容,不需要额外配置权限,只要Mutex名称符合当前应用的权限等级要求即可正常运行。

注意事项

  • 命名Mutex的名称要保证全局唯一,避免和其他应用的Mutex重名,建议前缀带上你的应用包名/唯一标识
  • 如果用于单实例启动逻辑,要在应用启动最早阶段初始化Mutex,比如在首个场景的Awake周期初始化,或者用[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]属性提前初始化
  • 应用退出时一定要主动释放Mutex句柄,否则可能出现Mutex被意外占用的异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 14:36:04