Mutex.WaitOne()始终返回true,寻求问题排查帮助
问题排查与修复方案
核心问题1:Mutex未实现跨应用互斥
你当前用new Mutex()创建的是本地互斥体,仅对当前进程内的线程生效,完全无法阻止其他应用(进程)获取锁,所以不管多少个应用调用这个方法,WaitOne()都会直接返回true。
要实现跨应用的互斥,必须创建命名全局互斥体,指定一个系统唯一的名称(注意名称不能和系统其他重名),格式为Global\XXX(加Global前缀确保跨Windows会话生效,比如服务和桌面应用之间)。
核心问题2:锁释放逻辑错误
你的finally块里不管有没有成功获取锁,都尝试调用ReleaseMutex()——如果WaitOne()返回false(比如设置了超时后未拿到锁),此时当前线程并没有持有锁,调用ReleaseMutex()会抛出异常(虽然你catch住了,但属于逻辑错误)。正确的做法是用一个标记记录是否成功获取锁,只在拿到锁的情况下释放。
修复后的代码
public static class BLStaticTask { // 创建全局命名互斥体,确保跨应用生效 private static readonly Mutex TasksMut = new Mutex(false, @"Global\Unique_Task_Handling_Mutex"); public static List<Tasks> GetTasksToHandle() { bool hasLock = false; try { // 可以设置超时时间,比如5000毫秒,避免无限等待 hasLock = TasksMut.WaitOne(5000); if (hasLock) { using (DBContext db = new DBContext()) { return db.prGetTasksToHandle().ToList(); } } else { // 超时未获取到锁,返回null或空列表 return null; } } catch { return null; } finally { // 仅当成功获取锁时,才释放 if (hasLock) { try { TasksMut.ReleaseMutex(); } catch { // 处理释放异常,比如日志记录 } } } } }
额外注意事项
- 命名互斥体的名称要确保唯一,建议用公司或项目前缀避免冲突。
- 如果是在非管理员权限的应用中使用
Global\前缀,可能需要权限设置,也可以用Local\前缀(仅当前用户会话内跨进程生效)。 - 记得添加超时时间,避免线程无限阻塞在
WaitOne()上。
内容的提问来源于stack exchange,提问作者Avihay Hatav
相关产品推荐
相关产品推荐

