Usei com sucesso um mutex, criado usando CreateMutex
set bInitialOwner
to TRUE
, para garantir que apenas uma única instância do aplicativo seja executada várias vezes sem problemas.
Minha expectativa era que isso também fosse dimensionado para permitir no máximo duas instâncias em execução simultâneas. Aqui está meu código com o objetivo de conseguir isso:
#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;
}
Depois de abrir o programa três vezes, obtive a saída desejada na terceira instância:
New instance started.
At least one instance is already running.
Checking if this is the second instance...
A second instance also exists already.
No entanto, mesmo depois de fechar todas as instâncias abertas, exceto uma (por uma questão de simplicidade, digamos que todas, exceto a terceira instância, foram fechadas), ainda recebo a saída acima e não a esperada:
New instance started.
No entanto, após fechar todas as instâncias, o programa se comporta novamente conforme o esperado. Isso me leva a acreditar que os mutexes só são liberados após todas as instâncias serem fechadas, porém a documentação afirma:
Use a função CloseHandle para fechar o identificador. O sistema fecha o identificador automaticamente quando o processo termina. O objeto mutex é destruído quando seu último identificador é fechado.
Portanto, eu esperava que o mutex fosse liberado assim que seu processo de propriedade terminasse.
Por que isso não parece ser o caso e como eu poderia usar mutexes para limitar meu aplicativo a duas instâncias?
Informações adicionais
Minha suspeita era que cada thread subseqüente também adquiriu um identificador chamando CreateMutexW
e, portanto, os mutexes só são destruídos quando o último identificador é fechado (por exemplo, a última instância em execução do "lote" é fechada e nenhuma outra instância está em execução).
Para atenuar isso pensei em simplesmente chamar CloseHandle
com o identificador o thread obtido, sempre que ERROR_ALREADY_EXISTS
for encontrado. O código que implementa isso está abaixo, mas leva exatamente ao mesmo comportamento descrito acima:
#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;
}
Editar: o código acima realmente se comporta da maneira que pretendi. Cometi um erro ao testá-lo (executando o binário antigo com o código inicial).