在处理回收的 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;
}

Linux:

#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;
}

相关内容