Skip to content

Instantly share code, notes, and snippets.

@ArunTS96
Created April 9, 2020 15:28
Show Gist options
  • Save ArunTS96/8426a8cfe5b20fb098ac696dd82f199f to your computer and use it in GitHub Desktop.
Save ArunTS96/8426a8cfe5b20fb098ac696dd82f199f to your computer and use it in GitHub Desktop.
Limiting your code to run only 'n' instance. c++. win32.
#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