You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 10:15:02