尝试打开互斥锁时的 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,名称冲突是不可能的。
这是唯一可以创建该互斥锁的代码,它为所有用户授予对它的完全访问权限(我的进程可以在不同的用户凭据下运行)。
任何想法,为什么会发生这种未经授权的访问错误?
这个类应该可以解决你的问题:
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
打开请求SYNCHRONIZE
和MUTEX_MODIFY
权限的命名互斥锁。
您看到的问题是创建互斥锁和安全描述符分配之间的简单竞争条件(至少据我所知)。使创建和安全描述符赋值原子化将解决这个问题。