【解决方案1】:

为了使用一个Windows 互斥体(无论是像您这样的命名还是未命名的),您需要使用以下 Win API:

<1234564> <1234563> CreateMutex - 获取互斥体 Windows kernel object 的句柄。如果是命名互斥锁(如您的),多个进程应该成功获取此句柄。第一个将导致操作系统创建一个新的命名互斥体,而其他人将获得一个指向同一个互斥体的句柄。
如果您获得了指定互斥锁的有效句柄,您可以通过检查GetLastError 是否返回ERROR_ALREADY_EXISTS 来确定互斥锁是否已经存在(即另一个进程已经创建了互斥锁)。<1234563> WaitForSingleObject - 锁定互斥锁以进行独占访问。这个函数实际上并不特定于互斥锁,它被用于许多内核对象。有关 Windows 内核对象的更多信息,请参阅上面的链接。<1234563> ReleaseMutex - 解锁互斥锁。<1234563> CloseHandle - 释放获取的互斥量句柄(与 Windows 句柄一样)。当进程存在时,操作系统会自动关闭句柄,但***明确地执行此操作。

一个完整的例子:

#include <Windows.h>
#include <iostream>

int main()
{
    // Create the mutex handle:
    HANDLE hMutex = ::CreateMutex(nullptr, FALSE, L"SingleInstanceMutex");
    if (!hMutex)
    {
        std::cout << "Failed to create mutex handle." << std::endl;
        // Handle error: ...
        return 1;
    }
    bool bAlreadyExisted = (GetLastError() == ERROR_ALREADY_EXISTS);
    std::cout << "Succeeded to create mutex handle. Already existed: " << (bAlreadyExisted ? "YES" : "NO") << std::endl;

    // Lock the mutex:
    std::cout << "Atempting to lock ..." << std::endl;
    DWORD dwRes = ::WaitForSingleObject(hMutex, INFINITE);
    if (dwRes != WAIT_OBJECT_0)
    {
        std::cout << "Failed to lock the mutex" << std::endl;
        // Handle error: ...
        return 1;
    }
    std::cout << "Locked." << std::endl;

    // Do something that required the lock: ...
    std::cout << "Press ENTER to unlock." << std::endl;
    std::getchar();

    // Unlock the mutex:
    if (!::ReleaseMutex(hMutex))
    {
        std::cout << "Failed to unlock the mutex" << std::endl;
        // Handle error: ...
        return 1;
    }
    std::cout << "Unlocked." << std::endl;

    // Free the handle:
    if (!CloseHandle(hMutex))
    {
        std::cout << "Failed to close the mutex handle" << std::endl;
        // Handle error: ...
        return 1;
    }

    return 0;
}

错误处理:
正如您在上面的文档链接中所见,当CreateMutexReleaseMutexCloseHandle 失败时,您应该调用GetLastError 以获取有关该错误的更多信息。 WaitForSingleObject 将在出错时返回一个特定的返回值(参见上面的文档链接)。这应该作为// Handle error: ... 部分的一部分来完成。

笔记:
为 IPC(进程间通信)使用命名互斥锁可能是本机 Windows 互斥锁的唯一好用例。
对于常规的未命名互斥锁,***使用可用的标准库类型之一的互斥锁:std::mutex,std::recursive_mutex,std::recursive_timed_mutex(最后两个支持线程重复锁定,类似于 Windows 互斥锁)。

【讨论】:

    <1234563>
    您好,谢谢您的回答,我尝试了代码,但仍然看不到 WinObj 中的互斥锁。这正常吗?
    <1234563>
    @Davide我不熟悉WinObj。但是你观察到互斥效应吗? (即,当第一个进程保持互斥锁锁定时,第二个进程保持在相关代码之外)。
    <1234563>
    不,我发现我使用的是 WinObj 而不是 WinObj64
    <1234563>
    是的,感谢是互斥的(:
    <1234563>
    如果您更彻底地解释具体情况会有所帮助,即如何确定 CreateMutex 是创建了新的互斥体还是返回了对现有互斥体的引用。至于有效的用例,Windows 原生互斥体具有与std::mutex 不同的属性,即拥有互斥体的线程可以重复等待它。 std::recursive_timed_mutex 将是更接近的匹配。尽管您可能应该使用SRW Lock 来代替。