Linux 以编程方式确定程序是否正在运行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6898337/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 05:24:17  来源:igfitidea点击:

Determine programmatically if a program is running

clinuxprocesspid

提问by Frank Vilea

In C, how can I find out programmatically if a process is already running on Linux/Ubuntu to avoid having it start twice? I'm looking for something similar to pidof.

在 C 中,如何以编程方式找出进程是否已经在 Linux/Ubuntu 上运行以避免它启动两次?我正在寻找类似于 pidof 的东西。

采纳答案by John Ledbetter

You can walk the pidentries in /procand check for your process in either the cmdlinefile or perform a readlinkon the exelink (The following uses the first method).

您可以pid输入条目/proc并检查cmdline文件中的进程或readlinkexe链接执行 a (以下使用第一种方法)。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>

pid_t proc_find(const char* name) 
{
    DIR* dir;
    struct dirent* ent;
    char* endptr;
    char buf[512];

    if (!(dir = opendir("/proc"))) {
        perror("can't open /proc");
        return -1;
    }

    while((ent = readdir(dir)) != NULL) {
        /* if endptr is not a null character, the directory is not
         * entirely numeric, so ignore it */
        long lpid = strtol(ent->d_name, &endptr, 10);
        if (*endptr != '
#include <sys/types.h>
#include <dirent.h>
#include<unistd.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

pid_t proc_find(const char* name) 
{
    DIR* dir;
    struct dirent* ent;
    char buf[512];

    long  pid;
    char pname[100] = {0,};
    char state;
    FILE *fp=NULL; 

    if (!(dir = opendir("/proc"))) {
        perror("can't open /proc");
        return -1;
    }

    while((ent = readdir(dir)) != NULL) {
        long lpid = atol(ent->d_name);
        if(lpid < 0)
            continue;
        snprintf(buf, sizeof(buf), "/proc/%ld/stat", lpid);
        fp = fopen(buf, "r");

        if (fp) {
            if ( (fscanf(fp, "%ld (%[^)]) %c", &pid, pname, &state)) != 3 ){
                printf("fscanf failed \n");
                fclose(fp);
                closedir(dir);
                return -1; 
            }
            if (!strcmp(pname, name)) {
                fclose(fp);
                closedir(dir);
                return (pid_t)lpid;
            }
            fclose(fp);
        }
    }


closedir(dir);
return -1;
}


int main(int argc, char* argv[]) 
{
    int i;
    if (argc == 1) {
        printf("usage: %s name1 name2 ...\n", argv[0]);
        return 1;
    }

    for( i = 1; i < argc; ++i) {
        pid_t pid = proc_find(argv[i]);
        if (pid == -1) {
            printf("%s: not found\n", argv[i]);
        } else {
            printf("%s: %d\n", argv[i], pid);
        }
    }

    return 0;
}
') { continue; } /* try to open the cmdline file */ snprintf(buf, sizeof(buf), "/proc/%ld/cmdline", lpid); FILE* fp = fopen(buf, "r"); if (fp) { if (fgets(buf, sizeof(buf), fp) != NULL) { /* check the first token in the file, the program name */ char* first = strtok(buf, " "); if (!strcmp(first, name)) { fclose(fp); closedir(dir); return (pid_t)lpid; } } fclose(fp); } } closedir(dir); return -1; } int main(int argc, char* argv[]) { if (argc == 1) { fprintf("usage: %s name1 name2 ...\n", argv[0]); return 1; } int i; for(int i = 1; i < argc; ++i) { pid_t pid = proc_find(argv[i]); if (pid == -1) { printf("%s: not found\n", argv[i]); } else { printf("%s: %d\n", argv[i], pid); } } return 0; }

回答by jmtd

pidof works by walking over the /procfilesystem. In C, you could do something similar by enumerating /proc; opening /proc/X/cmdlinefor every X where X is a list of one or more decimal numbers. I don't know if you have any portability requirements but bear that in mind if you are to rely on the availability of /proc.

pidof 通过遍历/proc文件系统来工作。在 C 中,您可以通过枚举来做类似的事情/proc/proc/X/cmdline为每个 X开头,其中 X 是一个或多个十进制数字的列表。我不知道您是否有任何可移植性要求,但如果您要依赖/proc.

This problem is more commonly solved on UNIX-like systems by wrapping the start-up of the program and maintaining a PID file. See /etc/init.d/*for classic examples of this approach. You will need to be careful to ensure that the code which reads of writes the PID file does so in a safe manner (atomically). If your target OS has a more capable init (such as systemd), you may be able to out source this work to that.

这个问题在类 UNIX 系统上通常通过包装程序的启动和维护一个 PID 文件来解决。有关/etc/init.d/*此方法的经典示例,请参见。您需要小心确保读取或写入 PID 文件的代码以安全的方式(原子地)执行此操作。如果您的目标操作系统具有更强大的 init(例如systemd),您可以将这项工作外包给那个。

回答by yuvaeasy

This is the same as the code posted by John Ledbetter . It is good to refer to the file named stat in /proc/pid/ directory than cmdline since the former gives process states and process name. The cmdline file gives complete arguments with which the process is started. So that fails in some cases. Any way the idea given by John is good. Here I posted the modified code of John. I was looking for the code in c in Linux to check dhcp is running or not . With this code, I am able to do that. I hope it may be useful for someone like me.

这与 John Ledbetter 发布的代码相同。引用 /proc/pid/ 目录中名为 stat 的文件比 cmdline 更好,因为前者给出了进程状态和进程名称。cmdline 文件提供了启动进程的完整参数。所以在某些情况下会失败。无论如何,约翰给出的想法都很好。这里我贴出了John的修改后的代码。我在 Linux 中寻找 c 中的代码来检查 dhcp 是否正在运行。有了这段代码,我就可以做到这一点。我希望它对我这样的人有用。

##代码##

回答by RCL

There are ways to avoid /procusage (and there might be good reasons to do so, e.g. /procmight not be installed at all, and/or it might have been symlinked to something deceptive, or that pid has been hidden in /proc). Granted, the below method doesn't look that good, I wish there were a proper API for that!

有一些方法可以避免/proc使用(并且可能有充分的理由这样做,例如/proc可能根本没有安装,和/或它可能已被符号链接到具有欺骗性的东西,或者 pid 已隐藏在 中/proc)。当然,下面的方法看起来不太好,我希望有一个合适的 API!

Anyway, section 1.9 of a 1997 Unix programming FAQsays:

无论如何,1997 年Unix 编程常见问题解答的第 1.9 节说:

Use kill()with 0 for the signal number. There are four possible results from this call:

使用kill()与0信号编号。此调用有四种可能的结果:

  • kill()returns 0

    This implies that a process exists with the given PID, and the system would allow you to send signals to it. It is system-dependent whether the process could be a zombie.

  • kill()returns -1, errno== ESRCH

    Either no process exists with the given PID, or security enhancements are causing the system to deny its existence. (On some systems, the process could be a zombie.)

  • kill()returns -1, errno== EPERM

    The system would not allow you to kill the specified process. This means that either the process exists (again, it could be a zombie) or draconian security enhancements are present (e.g. your process is not allowed to send signals to anybody).

  • kill()returns -1, with some other value of errno

    You are in trouble!

  • kill()返回 0

    这意味着存在具有给定 PID 的进程,系统将允许您向它发送信号。该进程是否可能是僵尸进程取决于系统。

  • kill()返回 -1,errno==ESRCH

    要么不存在具有给定 PID 的进程,要么安全增强导致系统拒绝其存在。(在某些系统上,该进程可能是僵尸进程。)

  • kill()返回 -1,errno==EPERM

    系统不允许您终止指定的进程。这意味着该进程存在(同样,它可能是僵尸)或存在严格的安全增强(例如,您的进程不允许向任何人发送信号)。

  • kill()返回 -1,还有一些其他值 errno

    你有麻烦了!

The most-used technique is to assume that success or failure with EPERMimplies that the process exists, and any other error implies that it doesn't.

最常用的技术是假设成功或失败EPERM意味着该过程存在,而任何其他错误则意味着它不存在。