C#命名信号量异常未释放死锁解决及Win32 C++同步机制咨询
问题根本原因
你使用的命名信号量没有进程所有权关联,操作系统内核无法追踪是哪个进程持有了信号量计数,因此当持有进程异常终止时,内核不会自动归还计数,导致后续等待的进程永久死锁。
C# 端解决方案
方案1:使用命名Mutex(推荐)
Mutex是带所有权的内核同步对象,持有进程异常退出时,内核会自动标记该Mutex为遗弃状态,下一个等待该Mutex的进程会收到通知并直接获得所有权,不会死锁。
示例代码:
using System; using System.Threading; namespace csharp_dot_net_frame { class Program { static void Main(string[] args) { try { // 第二个参数为false表示不直接占有Mutex,全局命名跨进程可见 using (Mutex mutex = new Mutex(false, "my_global_mutex")) { Console.WriteLine("Waiting for mutex"); try { mutex.WaitOne(); } catch (AbandonedMutexException) { // 捕获该异常说明前序持有进程异常退出,当前进程已获得Mutex所有权 Console.WriteLine("Detected abandoned mutex, lock acquired"); } Console.WriteLine("Mutex lock acquired"); Thread.Sleep(10000); mutex.ReleaseMutex(); Console.WriteLine("exiting."); } Console.ReadLine(); } catch(Exception e) { Console.WriteLine(e.Message); Console.ReadLine(); } } } }
方案2:使用文件排他锁(和UNIX lockf逻辑一致)
通过独占方式打开固定锁文件实现同步,进程退出时操作系统会自动释放所有打开的文件句柄,锁会自动释放,不会出现死锁。
示例代码:
using System; using System.IO; namespace csharp_dot_net_frame { class Program { static void Main(string[] args) { FileStream lockFileStream = null; try { // 独占方式打开锁文件,不存在则自动创建 lockFileStream = new FileStream("app_process.lock", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); Console.WriteLine("File lock acquired"); Thread.Sleep(10000); Console.WriteLine("exiting."); } catch (IOException) { // 抛出IO异常说明锁已被其他进程持有,可自行添加重试逻辑 Console.WriteLine("Waiting for file lock..."); } finally { lockFileStream?.Dispose(); // 可选:退出时删除锁文件 if(File.Exists("app_process.lock")) File.Delete("app_process.lock"); } Console.ReadLine(); } } }
Win32 C++ 端可靠同步机制推荐
1. 命名Mutex
和C#端逻辑一致,等待遗弃的Mutex会返回WAIT_ABANDONED状态码,此时当前线程已获得Mutex所有权,可正常使用。
示例代码:
#include <windows.h> #include <iostream> int main() { HANDLE hMutex = CreateMutexW(NULL, FALSE, L"my_global_mutex"); if (hMutex == NULL) { std::cout << "CreateMutex failed, error code: " << GetLastError() << std::endl; return 1; } std::cout << "Waiting for mutex" << std::endl; DWORD waitResult = WaitForSingleObject(hMutex, INFINITE); if (waitResult == WAIT_ABANDONED) { std::cout << "Detected abandoned mutex, lock acquired" << std::endl; } else if (waitResult == WAIT_OBJECT_0) { std::cout << "Mutex lock acquired" << std::endl; } else { std::cout << "Wait failed, error code: " << GetLastError() << std::endl; CloseHandle(hMutex); return 1; } Sleep(10000); ReleaseMutex(hMutex); std::cout << "exiting." << std::endl; CloseHandle(hMutex); system("pause"); return 0; }
2. 文件锁
使用LockFile/LockFileExAPI实现文件区域锁,逻辑和UNIX的lockf完全一致,进程异常退出时操作系统会自动释放所有持有锁,无死锁风险。
3. 其他可选内核对象
带遗弃检测的同步对象都可以满足需求,日常使用优先选Mutex或者文件锁即可。
内容的提问来源于stack exchange,提问作者dragon
相关产品推荐
相关产品推荐

