재활용된 PID를 처리할 때 PID의 프로세스가 활성화되어 있는지 확인하세요.

재활용된 PID를 처리할 때 PID의 프로세스가 활성화되어 있는지 확인하세요.

내가 온라인에서 본 바에 따르면 C++에서 kill 메소드를 호출하여 프로세스가 아직 살아 있는지 확인합니다. 문제는 PID가 순환되고 있고 찾고 있는 동일한 PID가 동일한 프로세스가 아닐 수 있다는 것입니다. 서로의 자식이 아닌 두 개의 프로세스가 있는 프로그램이 있습니다. 그들과 소통할 수 있는 유일한 방법은 IPC입니다. 클라이언트 프로세스가 종료되면 내 호스트 프로세스도 종료되기를 원합니다. 이를 위해서는 클라이언트의 프로세스가 더 이상 존재하지 않는 시기를 알아야 합니다.

Windows에는 핸들을 생성한 프로세스가 닫힐 때까지 PID가 재활용되지 않도록 하는 소위 프로세스 핸들러가 있습니다. macOS/Linux(POSIX) 시스템에서 이를 구현하는 방법을 알고 싶습니다.

문제의 코드는 PID로 재활용됩니다.

if (0 == kill(pid, 0))
{
    // Process exists.
}

답변1

내가 온라인에서 본 바에 따르면 C++에서 kill 메소드를 호출하여 프로세스가 아직 살아 있는지 확인합니다. 문제는 PID가 루프되고 있고 찾고 있는 동일한 PID가 동일한 프로세스가 아닐 수 있다는 것입니다.

그렇습니다. 따라서 이 kill접근 방식은아니요일하다. 사실 이야기는 여기서 끝난다. 효과적인 도구는 아닙니다.

두 가지 옵션:

  • 모니터링 중인 프로세스가 자신의 하위 프로세스(또는 자신의 프로세스 그룹에 있는 프로세스)인 경우 waitpid특히 종료 시점을 모니터링하세요.
  • 프로세스가 다음과 같은 경우아니요자식 프로세스와 관련하여 POSIX "이상적"은 자신의 프로세스가 반드시 해당 프로세스의 수명 주기와 밀접하게 상호 작용할 필요는 없다고 말합니다(적어도 이것이 waitpid제한 사항에서 내린 결론입니다). "추적" 권한을 갖고 이를 사용하여 ptrace다른 프로세스에 연결하고 exit호출을 기다릴 수 있습니다.

답변2

해결책은PID 유지창문으로 지나가세요은닉처시스템 process handle의 경우 간단히 시작합니다.POSIX핵심 OS DEPENDANT!그런 다음 캐시된 시작 시간이 현재 시작 시간과 같은지 확인하세요. PID 충돌이 감지되지 않으면 false가 반환됩니다.

윈도우:

#include <windows.h>
#include <iostream>
#include <vector>
#include <map>

map<DWORD, HANDLE> handles;
bool isProcessAlive(DWORD pid)
{
    HANDLE process;
    if(handles.find(pid) == handles.end())
    {
        process = OpenProcess(SYNCHRONIZE, FALSE, pid);
        handles[pid] = process;
    }
    else
    {
        process = handles[pid];
    }
    DWORD ret = WaitForSingleObject(process, 0);
    bool isRunning = ret == WAIT_TIMEOUT;
    if(!isRunning)//close the cached handle to free the PID and erase from the cache
    {
        CloseHandle(process);
        handles.erase(pid);
    }
    return isRunning;
}

애플 시스템:

#include <signal.h>
#include <stddef.h>
#include <sys/_types/_timeval.h>
#include <sys/errno.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <cstring>
#include <iostream>
#include <map>
#include <string>
/**
 * map of unsigned long, creation time either in jiffies, ms, or in clock ticks or different on mac even. so we keep it as a string
 */
std::map<unsigned long, string> handles;
/**
 * returns true if the process is alive and attempts to suggest a handle to linux's os that we are reading the directory /proc/[PID] reserve this PID till program shutdown
 */
bool isProcessAlive(unsigned long pid)
{
    // Get process info from kernel
    struct kinfo_proc info;
    int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid };
    size_t len = sizeof info;
    memset(&info,0,len);
    int rc = sysctl(mib, (sizeof(mib)/sizeof(int)), &info, &len, NULL, 0);

    //exit program sysctl failed to verify PID
    if (rc != 0)
    {
        handles.erase(pid);
        return false;
    }

    //extract start time and confirm PID start time equals org start time
    struct timeval tv = info.kp_proc.p_starttime;
    if(tv.tv_sec == 0)
    {
        handles.erase(pid);
        return false;
    }
    string time = to_string(tv.tv_usec) + "-" + to_string(tv.tv_sec);
    if(handles.find(pid) != handles.end())
    {
        string org_time = handles[pid];
        if(org_time != time)
        {
            cout << "PID Conflict PID:" << pid << " org_time:" + org_time << " new_time:" << time << endl;
            handles.erase(pid);
            return false;
        }
    }
    else
    {
        handles[pid] = time;
    }
    return true;
}

리눅스:

#include <iostream>
#include <vector>
#include <map>
#include <signal.h>
#include <dirent.h>
#include <errno.h>
#include <fstream>

#include <iostream>
#include <iterator>
#include <sstream>
#include <fstream>
#include <vector>
#include <cstring>
#include <cerrno>
#include <ctime>
#include <cstdio>
#include <fcntl.h>
#include <sys/time.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string>
#include "/usr/include/x86_64-linux-gnu/sys/param.h"

/**
 * map of unsigned long, creation time either in jiffies, ms, or in clock ticks or different on mac even. so we keep it as a string
 */
std::map<unsigned long, string> handles = {};
/**
 * returns true if the process is alive and attempts to suggest a handle to linux's os that we are reading the directory /proc/[PID] reserve this PID till program shutdown
 */
bool isProcessAlive(unsigned long pid)
{
    ifstream procFile;
    string f = "/proc/"+ std::to_string(pid)+ "/stat";
    procFile.open(f.c_str());
    if(!procFile.fail())
    {
        //get creation time of current pid's process
        char str[255];
        procFile.getline(str, 255);  // delim defaults to '\n'

        vector<string> tmp;
        istringstream iss(str);
        copy(istream_iterator<string>(iss),
             istream_iterator<string>(),
             back_inserter<vector<string> >(tmp));

        string creation_time = tmp.at(21);

        //check if the process's creation time matches the cached creation time
        if(handles.find(pid) != handles.end())
        {
            string org = handles[pid];
            //if the pid's creation time is not the cached creation time we assume it's not the same process and the original has closed
            //unlike java the ==,!= actually checks .equals() when comparing
            if(creation_time != org)
            {
                std::cerr << "PID conflict:" + to_string(pid) + " orgCreationTime:" + org + " newCreationTime:" + creation_time;
                handles.erase(pid);
                procFile.close();
                return false;
            }
        }
        handles[pid] = creation_time;
        procFile.close();
        return true;
    }
    handles.erase(pid);
    procFile.close();
    return false;
}

관련 정보