尝试打开互斥锁时的 UnauthorizedAccessException

本文关键字:UnauthorizedAccessException | 更新日期: 2023-09-27 18:36:28

我在尝试打开互斥锁时遇到此异常(它只是偶尔发生;大多数调用都是成功的):

System.UnauthorizedAccessException: Access to the path 'Global'4c7cddf7-e729-43b6-a75c-43f54a0ac6ac' is denied.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.Threading.Mutex.OpenExisting(String name, MutexRights rights)

我用来处理互斥锁的代码:

public class MutexLocker : IDisposable
{
    public MutexLocker(string id)
    {
        var doesNotExist = false;
        var unauthorized = false;
        try
        {
            _mutex = Mutex.OpenExisting(id, MutexRights.Synchronize | MutexRights.Modify);
        }
        catch (WaitHandleCannotBeOpenedException)
        {
            doesNotExist = true;
        }
        catch (UnauthorizedAccessException ex)
        {
            unauthorized = true;
        }
        if (doesNotExist)
        {
            _mutex = new Mutex(false, id);
            var allowEveryoneRule = new MutexAccessRule(
                new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
            var securitySettings = new MutexSecurity();
            securitySettings.AddAccessRule(allowEveryoneRule);
            _mutex.SetAccessControl(securitySettings);
        }
        else if (unauthorized)
        {
            var tempMutex = Mutex.OpenExisting(id, MutexRights.ReadPermissions | MutexRights.ChangePermissions);
            var securitySettings = tempMutex.GetAccessControl();
            var user = Environment.UserDomainName + "''" + Environment.UserName;
            // the rule that denied the current user the right to enter and release the mutex must be removed
            var rule = new MutexAccessRule(user, MutexRights.Synchronize | MutexRights.Modify, AccessControlType.Deny);
            securitySettings.RemoveAccessRule(rule);
            // Now grant the correct rights
            var allowEveryoneRule = new MutexAccessRule(
                new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
            securitySettings.AddAccessRule(allowEveryoneRule);
            tempMutex.SetAccessControl(securitySettings);
            _mutex = Mutex.OpenExisting(id, MutexRights.Synchronize | MutexRights.Modify);
        }
        var success = _mutex.WaitOne(TimeSpan.FromSeconds(10), false);
        if (success == false)
        {
            _mutex.Dispose();
            _mutex = null;
            throw new ApplicationException(string.Format("Can't lock mutex (timed out): {0}", id));
        }
    }
    public void Dispose()
    {
        if (_mutex != null)
        {
            try
            {
                _mutex.ReleaseMutex();
            }
            catch (Exception exc)
            {
                Trace.WriteLine(exc);
            }
            _mutex.Dispose();
        }
    }
    private readonly Mutex _mutex;
}

互斥体"id"是一个 GUID,名称冲突是不可能的。
这是唯一可以创建该互斥锁的代码,它为所有用户授予对它的完全访问权限(我的进程可以在不同的用户凭据下运行)。

任何想法,为什么会发生这种未经授权的访问错误?

尝试打开互斥锁时的 UnauthorizedAccessException

这个类应该可以解决你的问题:

    public class MutexLocker: IDisposable
    {
        private Mutex _mutex;
        public MutexLocker ( string id )
        {
            bool createdNew;
            MutexSecurity mutexSecurity = new MutexSecurity();
            mutexSecurity.AddAccessRule(new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), 
                                                            MutexRights.Synchronize | MutexRights.Modify, AccessControlType.Allow));
            try
            {
                // attempt to create the mutex, with the desired DACL..
                _mutex = new Mutex(false, id, out createdNew, mutexSecurity);
            }
            catch (WaitHandleCannotBeOpenedException)
            {
                // the mutex cannot be opened, probably because a Win32 object of a different
                // type with the same name already exists.
                throw;
            }
            catch (UnauthorizedAccessException)
            {
                // the mutex exists, but the current process or thread token does not
                // have permission to open the mutex with SYNCHRONIZE | MUTEX_MODIFY rights.
                throw;
            }
        }
        public void Dispose ()
        {
            if (_mutex != null)
            {
                _mutex.ReleaseMutex();
                _mutex.Dispose();
            }
            _mutex = null;
        }
    }

唯一需要注意的是互斥构造函数,它将尝试创建互斥锁(通过调用 Win32 的 CreateMutex() ),立即将提供的安全描述符分配给命名对象。如果 CreateMutex 调用失败,框架将尝试使用 OpenMutex 打开请求SYNCHRONIZEMUTEX_MODIFY权限的命名互斥锁。

您看到的问题是创建互斥锁和安全描述符分配之间的简单竞争条件(至少据我所知)。使创建和安全描述符赋值原子化将解决这个问题。

相关文章:
  • 没有找到相关文章