Разрешить запуск только n экземпляра программы - PullRequest
0 голосов
/ 10 апреля 2020

Существует множество примеров, позволяющих запускать только один экземпляр программы. Но мне нужно, чтобы мне нужно было запускать «N» (например, N = 5) экземпляров приложения, но не превышать его. Я не смог найти в Интернете никаких ресурсов по этому поводу.

class InstanceMaintainer{
private:
    HANDLE h_ = nullptr;

public:
    InstanceMaintainer(const std::string& programName, unsigned maxInstances, unsigned& obtainedInstanceId){
        const auto semOrMutexName = "Global\\" + programName;
        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_, 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");
        }
    }

    ~InstanceMaintainer(){
        ReleaseMutex(h_);
        CloseHandle(h_);
    }
};

int main(){
    try{
        unsigned instanceId = -1;
        InstanceMaintainer im("Quickie", 7, instanceId);
        std::cout << "Running " << instanceId << "\n";
    }catch (std::exception& e){
        std::cout << e.what() << "\n";
    }

    return 0;
}

Это то, что я придумал. Это windows конкретный c. Есть ли c ++ стандартный способ сделать это? Как обходится отсутствие именованного мьютекса в std :: mutex? Я знаю, что есть названный семафор в c ++ posix. Но он не может вернуть идентификатор экземпляра, что, в свою очередь, будет полезно для доступа к ресурсам.

...