YOGYUI

C++::Linux에서 프로그램 중복 실행 방지 본문

Software/C, C++

C++::Linux에서 프로그램 중복 실행 방지

요겨 2022. 8. 23. 07:43
반응형

C++::Prevent duplicated execution (Linux)

지난 포스팅에서 특정 프로세스의 ID값(PID)들을 조회하는 코드를 구현해봤다

C++::Linux에서 특정 프로세스의 ID값(PID) 읽어오기 (pidof 명령어)

 

C++::Linux에서 특정 프로세스의 ID값(PID) 읽어오기 (pidof 명령어)

C++::Get PID of specific process using 'pidof' command (Linux) 리눅스에서 특정 프로세스의 ID(PID)값을 읽어오는 C++코드를 작성해봤다 모든 코드는 Ubuntu 20.04.4 LTS 환경에서 테스트함 1. 터미널 명령어..

yogyui.tistory.com

 

이를 활용해 프로그램의 중복 실행을 방지할 수 있는 코드를 작성해보자

모든 코드는 Ubuntu 20.04.4 LTS 환경에서 테스트함

1. 코드 구현

#include <cstdio>
#include <vector>
#include <unistd.h>
#include <string>
#include <cstring>
#include <sstream>
#include <algorithm>

void get_process_id_list(const char *proc_name, std::vector<pid_t> &list) {
    char command[256]{0, };
    char result[256]{0, };

    sprintf(command, "pidof %s", proc_name);
    // get "pidof" result as string
    FILE *fp = popen(command, "r");
    list.clear();
    if (fp) {
        size_t ret = fread(result, 1, 256, fp);
        pclose(fp);
        if (ret <= 0) {
            printf("failed to get pidof command result\n");
            return;
        }
        // convert as std::string and remove new line character(\n)
        std::string szres(result);
        szres.replace(szres.find('\n'), 1, "");
        // split string and push pid values in vector (delimeter = ' ')
        std::string szpid;
        std::istringstream stream(szres);
        while (getline(stream, szpid, ' ')) {
            pid_t pid = strtol(szpid.c_str(), nullptr, 10);
            list.push_back(pid);
        }
    }
}

bool check_executable(const char *proc_name) {
    std::vector<pid_t> pid_list;
    // get pid list of specific process
    get_process_id_list(proc_name, pid_list);
    // get pid of current process and remove it from vector 
    pid_t my_pid = getpid();
    pid_list.erase(std::remove(pid_list.begin(), pid_list.end(), my_pid), pid_list.end());
    // check size of vector (if not empty, process is duplicated)
    if (!pid_list.empty()) {
        printf("Found other process which is running (count: %zu)\n", pid_list.size());
        for (auto &pid : pid_list) {
            printf("%d\n", pid);
        }
        return false;
    }

    return true;
}

check_executable 함수 호출 시, 특정 프로세스의 PID값들을 벡터(pid_t형)에 담은 후, 현재 실행중인 프로세스의 PID값이 존재할 경우 벡터에서 지운 뒤 벡터의 크기가 1 이상일 경우 (=not empty) 해당 프로세스가 중복 실행되었다고 판단할 수 있게 구현해봤다

※ <unistd.h>내의 getpid() 함수를 호출하면 현재 실행중인 프로세스의 PID값을 쉽게 얻을 수 있다

2. 테스트

테스트를 위해 main.cpp 스크립트를 간단하게 작성해보자

extern char *__progname;

int main(int argc, char *argv[]) {
    pid_t my_pid = getpid();
    if (!check_executable(__progname)) {
        return 1;
    } else {
        while (1) {
            printf("process <%s (PID %d)> is running\n", __progname, my_pid);
            sleep(5);
        }
    }

    return 0;
}

현재 실행중인 프로세스의 이름은 argv[0]를 활용하는게 일반적인데, 만약 __progname 전역변수를 사용할 수 있는 환경이라면 이를 활용하는게 훨씬 편하다 (물론 이식성은 떨어진다는게 단점이지만..)

 

g++로 실행 파일을 빌드해주자 (실행파일명은 test로 임의 지정)

$ g++ -g main.cpp -o test

이제 터미널 2개를 열어 각 터미널에서 프로그램을 실행해보자

프로그램 최초 실행 시
두번째 프로그램 실행 시
System Monitor 툴

최초 프로그램 실행 시 PID 134663으로 프로세스가 실행된 뒤 while문이 계속 돌게 되는데, 이 때 두번째 실행 시 다른 프로세스가 실행중이라는 메시지와 함께 프로그램이 종료된다 (while문으로 가지 않고 return)

3. Github repository

※ Windows 기반 프로그램을 Linux 환경으로 포팅하는 과정에서 이것저것 필요한 코드들을 정리해서 깃허브에 올리고 있다

https://github.com/YOGYUI/Sniffets/tree/main/linux_prevent_duplicated_execution/src

 

GitHub - YOGYUI/Sniffets: 간단한 예제 코드들

간단한 예제 코드들. Contribute to YOGYUI/Sniffets development by creating an account on GitHub.

github.com

 

Windows OS에서는 MFC의 CreateMutex API로 간단하게 뮤텍스 기반 중복 실행 방지 구문을 만들 수 있는데(길어봐야 코드 2~3줄?), Linux는 조금은 번거롭게 구현해야만 했다 

그래도 process id는 이곳 저곳에서 쓸 일이 많으니 이참에 방법을 확실히 알아냈다는데 의의를 둬야겠다

끝~!

 

 

[참고]

https://www.qnx.com/developers/docs/7.1/index.html#com.qnx.doc.neutrino.lib_ref/topic/p/__progname.html 

https://stackoverflow.com/questions/3385229/c-erase-vector-element-by-value-rather-than-by-position

반응형
Comments