在 .NET 中使用 Mutex 和内存文件进行权限控制

本教程讲解了在 .NET 中如何正确使用 Mutex 和 MemoryMappedFile 进行进程间通信(IPC),特别是在涉及 Windows 服务时如何设置安全权限。

在 .NET 中进行进程间通信(IPC)时,Mutex(互斥体)和 MemoryMappedFile(内存映射文件)是常用的工具。然而,当其中一个进程是 Windows 服务时,由于权限差异,可能会遇到访问问题。本文将介绍如何正确设置权限,并强调一个使用 Mutex 时的重要注意事项。

Mutexawait 的陷阱

在使用 Mutex 时,一个至关重要的原则是:必须在同一个线程上获取和释放锁

Mutex.WaitOne() 会阻塞当前线程,直到获取到锁。Mutex.ReleaseMutex() 则会释放锁。如果你在 WaitOne()ReleaseMutex() 之间使用了 await 关键字,await 后面的代码可能会由线程池中的另一个不同线程执行。如果发生这种情况,ReleaseMutex() 将在一个未获取锁的线程上被调用,从而抛出 ApplicationException

警告:Mutex.WaitOne()Mutex.ReleaseMutex() 方法之间 绝对不能 执行 await 操作。

Windows 服务下的权限控制

当普通桌面应用程序与 Windows 服务之间进行 IPC 时,会遇到权限问题。这是因为 Windows 服务通常在 Local SystemLocal ServiceNetwork Service 等具有不同权限的账户下运行,而桌面应用则在当前登录用户的账户下运行。

为了让这两个进程能够共享 MutexMemoryMappedFile 等命名的内核对象,你需要为这些对象明确设置访问控制规则(ACL)。

下面的示例代码展示了如何为当前用户授予对全局 MutexMemoryMappedFile 的完全控制权限。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System.IO.MemoryMappedFiles;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Threading;

// 获取当前用户的身份信息
WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
string user = currentUser.Name;

// 1. 创建或打开一个全局 Mutex 并设置权限
// "Global\\" 前缀确保对象在所有终端服务会话中可见
var mutex = new Mutex(false, "Global\\mutex_ZhongRuanPMS");

// 创建一个访问规则,授予当前用户完全控制权限
var maRule = new MutexAccessRule(user, MutexRights.FullControl, AccessControlType.Allow);

// 获取现有的安全设置并添加新的规则
MutexSecurity mSec = mutex.GetAccessControl();
mSec.AddAccessRule(maRule);
mutex.SetAccessControl(mSec); // 应用新的安全设置

// 2. 创建或打开一个全局内存映射文件并设置权限
var memoryMappedFile = MemoryMappedFile.CreateOrOpen("Global\\mmf_ZhongRuanPMS", 20480, MemoryMappedFileAccess.ReadWrite);

// 为内存映射文件创建类似的访问规则
var mmfRule = new AccessRule<MemoryMappedFileRights>(user, MemoryMappedFileRights.FullControl, AccessControlType.Allow);

// 获取现有的安全设置并添加新的规则
MemoryMappedFileSecurity msc = memoryMappedFile.GetAccessControl();
msc.AddAccessRule(mmfRule);
memoryMappedFile.SetAccessControl(msc); // 应用新的安全设置

通过这种方式,即使应用程序和 Windows 服务在不同的安全上下文中运行,它们也可以成功地访问和同步这些共享的内核对象。

Built with Hugo
Theme Stack designed by Jimmy