CreateMutex
创建的互斥锁,并将 bInitialOwner
设置为 TRUE
,以确保仅单个应用程序实例运行,多次运行,不会出现任何问题。
我的期望是,这也将扩展到允许最多两个同时运行的实例。这是我旨在实现这一目标的代码:
#include <windows.h>
#include <synchapi.h>
#include <codecvt>
#include <chrono>
#include <iostream>
#include <thread>
int main() {
std::cout << "New instance started.\n";
HANDLE mutex_handle = CreateMutexW(0, TRUE, L"myMutex1");
if (GetLastError() == ERROR_ALREADY_EXISTS) {
std::cout << "At least one instance is already running.\nChecking if this is the second instance...\n";
HANDLE mutex_handle2 = CreateMutexW(0, TRUE, L"myMutex2");
if (GetLastError() == ERROR_ALREADY_EXISTS) {
std::cout << "A second instance also exists already.\n";
}
}
// In every case wait for 25 seconds to simulate a long running program (e.g. GUI, etc.).
std::this_thread::sleep_for(std::chrono::milliseconds(25000));
return 0;
}
打开程序三次后,我在第三次实例中得到了所需的输出:
New instance started.
At least one instance is already running.
Checking if this is the second instance...
A second instance also exists already.
但是,即使关闭了除一个打开的实例之外的所有实例(为了简单起见,假设除了第三个实例之外的所有实例都已关闭),我仍然得到上面的输出,而不是预期的:
New instance started.
但是,关闭所有实例后,程序将再次按预期运行。这让我相信,互斥体只有在所有实例关闭后才会被释放,但是文档指出:
使用 CloseHandle 函数关闭句柄。当进程终止时系统自动关闭句柄。当互斥对象的最后一个句柄关闭时,该对象将被销毁。
因此,我希望互斥体在其所属进程终止后就会被释放。
为什么情况似乎并非如此?我如何使用互斥体将我的应用程序限制为两个实例?
我的怀疑是,每个后续线程也通过调用
CreateMutexW
获取了一个句柄,因此只有当最后一个句柄关闭时,互斥体才会被销毁(例如,“批处理”的最后一个运行实例被关闭,并且没有更多实例正在运行) .
为了缓解这种情况,我认为只要遇到 CloseHandle
,我就可以使用线程获得的句柄调用
ERROR_ALREADY_EXISTS
。实现此功能的代码如下,但这会导致与上述完全相同的行为:
#include <windows.h>
#include <synchapi.h>
#include <codecvt>
#include <chrono>
#include <iostream>
#include <thread>
int main() {
std::cout << "New instance started.\n";
HANDLE mutex_handle = CreateMutexW(0, TRUE, L"myMutex1");
if (GetLastError() == ERROR_ALREADY_EXISTS) {
if (mutex_handle != NULL)
{
CloseHandle(mutex_handle);
}
std::cout << "At least one instance is already running.\nChecking if this is the second instance...\n";
HANDLE mutex_handle2 = CreateMutexW(0, TRUE, L"myMutex2");
if (GetLastError() == ERROR_ALREADY_EXISTS) {
if (mutex_handle2 != NULL)
{
CloseHandle(mutex_handle2);
}
std::cout << "A second instance also exists already.\n";
}
}
// In every case wait for 25 seconds to simulate a long running program (e.g. GUI, etc.).
std::this_thread::sleep_for(std::chrono::milliseconds(25000));
return 0;
}
互斥锁仅处于活动或非活动状态。如果您希望传递非二进制数量的等待调用,则可以使用专门为此设计的原语,例如 semaphores,它可以定义要传递的最大调用数量(在您的情况下为 2)。
这种方法的唯一问题是,与互斥体不同,您还需要处理应用程序关闭(以减少信号量计数,以便另一个实例可以“进入”)。一般来说,如果您一次需要 2 个实例,则没有理由不允许任意数量的实例。