Created
April 9, 2020 15:28
-
-
Save ArunTS96/8426a8cfe5b20fb098ac696dd82f199f to your computer and use it in GitHub Desktop.
Limiting your code to run only 'n' instance. c++. win32.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Windows.h> | |
#include <string> | |
#include <iostream> | |
#define USE_MUTEX | |
class InstanceMaintainer | |
{ | |
private: | |
HANDLE h_ = nullptr; | |
static InstanceMaintainer* instance_; | |
#ifndef USE_MUTEX | |
InstanceMaintainer(const std::string& programName, unsigned maxInstances) | |
#else | |
InstanceMaintainer(const std::string& programName, unsigned maxInstances, unsigned& obtainedInstanceId) | |
#endif | |
{ | |
const auto semOrMutexName = "Global\\" + programName; | |
#ifndef USE_MUTEX | |
h_ = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, TRUE, semName.c_str()); | |
if (h_ == nullptr) | |
{ | |
if (GetLastError() == ERROR_FILE_NOT_FOUND) | |
{ | |
h_ = CreateSemaphoreA(nullptr, maxInstances - 1, maxInstances, semName.c_str()); | |
if (h_ == nullptr) | |
{ | |
const auto err = "Creating semaphore failed " + std::to_string(GetLastError()); | |
throw std::exception(err.c_str()); | |
} | |
} | |
else | |
{ | |
const auto err = "Opening semaphore failed " + std::to_string(GetLastError()); | |
throw std::exception(err.c_str()); | |
} | |
} | |
const auto dwWaitResult = WaitForSingleObject( | |
h_, // handle to semaphore | |
0L); | |
if (dwWaitResult == WAIT_TIMEOUT) | |
throw std::exception("Max number of instances reached\n"); | |
#else | |
obtainedInstanceId = -1; | |
for (unsigned i = 0; i < maxInstances; i++) | |
{ | |
auto mutexName = semOrMutexName + std::to_string(i); | |
h_ = OpenMutexA(MUTEX_ALL_ACCESS, FALSE, mutexName.c_str()); | |
if (h_ != nullptr) | |
{ | |
const auto dwWaitResult = WaitForSingleObject( | |
h_, // handle to mutex | |
0L); | |
if (dwWaitResult == WAIT_TIMEOUT) | |
{ | |
CloseHandle(h_); | |
h_ = nullptr; | |
} | |
else | |
{ | |
obtainedInstanceId = i; | |
break; | |
} | |
} | |
else | |
{ | |
if (GetLastError() == ERROR_FILE_NOT_FOUND) | |
{ | |
h_ = CreateMutexA(nullptr, TRUE, mutexName.c_str()); | |
if (h_ == nullptr) | |
{ | |
const auto err = "CreateMutex failed with " + std::to_string(GetLastError()); | |
throw std::exception(err.c_str()); | |
} | |
else | |
{ | |
obtainedInstanceId = i; | |
break; | |
} | |
} | |
else | |
{ | |
const auto err = "OpenMutex failed with " + std::to_string(GetLastError()); | |
throw std::exception(err.c_str()); | |
} | |
} | |
} | |
if (obtainedInstanceId == unsigned(-1)) | |
{ | |
throw std::exception("All instances are already taken\n"); | |
} | |
#endif | |
} | |
~InstanceMaintainer() | |
{ | |
#ifndef USE_MUTEX | |
ReleaseSemaphore(h_, 1, nullptr); | |
#else | |
ReleaseMutex(h_); | |
#endif | |
CloseHandle(h_); | |
} | |
public: | |
InstanceMaintainer& operator=(const InstanceMaintainer&) = delete; //copy assignment operator(assign const lvalue reference) | |
InstanceMaintainer(const InstanceMaintainer&) = delete; //copy constructor(const lvalue reference) | |
InstanceMaintainer(InstanceMaintainer&&) = delete; //move constructor(rvalue reference) | |
InstanceMaintainer& operator=(InstanceMaintainer&&) = delete; //move assignment operator(assign rvalue reference) | |
#ifndef USE_MUTEX | |
static InstanceMaintainer* GetInstance(const std::string& programName, const unsigned maxInstances) | |
#else | |
static InstanceMaintainer* GetInstance(const std::string& programName, const unsigned maxInstances, unsigned& obtainedInstanceId) | |
#endif | |
{ | |
if (instance_ == nullptr) | |
#ifndef USE_MUTEX | |
instance_ = new InstanceMaintainer(programName, maxInstances); | |
#else | |
instance_ = new InstanceMaintainer(programName, maxInstances, obtainedInstanceId); | |
#endif | |
return instance_; | |
} | |
}; | |
InstanceMaintainer* InstanceMaintainer::instance_ = nullptr; | |
int main() | |
{ | |
try | |
{ | |
unsigned instanceId = -1; | |
std::cout << instanceId << "\n"; | |
auto im = InstanceMaintainer::GetInstance("Quickie", 7, instanceId); | |
std::cout << "Running " << instanceId << "\n"; | |
system("pause"); | |
} | |
catch (std::exception& e) | |
{ | |
std::cout << e.what() << "\n"; | |
system("pause"); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment