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

时间:2011-08-01 12:22:14

标签: c linux process pid

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

4 个答案:

答案 0 :(得分:29)

您可以浏览pid中的/proc条目,并在cmdline文件中检查您的流程,或在readlink链接上执行exe(以下使用第一种方法。)

#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 != '\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;
}

答案 1 :(得分:13)

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

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

答案 2 :(得分:13)

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

无论如何,1997年{1.9}的第1.9节说:

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

  • kill()返回0

    这意味着存在一个具有给定PID的进程,并且       系统允许您向其发送信号。它是       系统依赖于该过程是否可能是一个僵尸。

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

    对于给定的PID或安全性,不存在任何进程       增强功能导致系统否认其存在。 (上       在某些系统中,这个过程可能是一个僵尸。)

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

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

  • kill()返回-1,其他值为errno

    你遇到了麻烦!

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

答案 3 :(得分:3)

pidof在/proc filesystem上行走。在C中,您可以通过枚举/proc来执行类似的操作;为每个X打开/proc/X/cmdline,其中X是一个或多个十进制数的列表。我不知道您是否有任何可移植性要求,但如果您要依赖/proc的可用性,请记住这一点。

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