CreateMutex
我成功地使用了一个互斥体,该互斥体是使用bInitialOwner
set to创建的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;
}
编辑:上面的代码实际上确实按照我的预期方式运行。我在测试它时犯了一个错误(通过使用初始代码运行旧的二进制文件)。
您在拥有状态下创建互斥体,但不会调用
ReleaseMutex
让其他进程进入。由于您仅使用互斥体来计算实例而不执行任何其他同步,因此只需将它们创建为“无主”就足够了 - 如果您尝试创建的互斥锁已存在,请关闭它并尝试下一步,直到达到最大实例数。它可能看起来像这样:
你可以像这样使用它。以下是最多允许 3 个实例的示例:
互斥锁仅处于活动或非活动状态。如果您希望传递非二进制数量的等待调用,则可以使用专门为此设计的原语,例如semaphores,它可以定义要传递的最大调用数量(在您的情况下为 2)。
这种方法的唯一问题是,与互斥体不同,您还需要处理应用程序关闭(以减少信号量计数,以便另一个实例可以“进入”)。一般来说,如果您同时需要 2 个实例,则没有理由不允许任意数量的实例。