Определить программно, если программа работает - PullRequest
27 голосов
/ 01 августа 2011

В C, как я могу узнать программно, если процесс уже запущен в Linux / Ubuntu, чтобы избежать его запуска дважды? Я ищу что-то похожее на pidof.

Ответы [ 4 ]

29 голосов
/ 01 августа 2011

Вы можете просмотреть записи 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;
}
13 голосов
/ 06 ноября 2013

Есть способы избежать использования /proc (и для этого могут быть веские причины, например, /proc может вообще не быть установлен, и / или он был связан с чем-то обманчивым, или что pid имеет был спрятан в /proc). Конечно, приведенный ниже метод выглядит не очень хорошо, хотелось бы, чтобы для этого был подходящий API!

В любом случае, раздел 1.9 из 1997 FAQ по программированию в Unix говорит:

Используйте kill() с 0 для номера сигнала. У этого звонка четыре возможных результата:

  • kill() возвращает 0

    Это подразумевает, что процесс существует с данным PID, и Система позволит вам отправлять сигналы на него. это зависит от системы, может ли процесс быть зомби.

  • kill() возвращает -1, errno == ESRCH

    Либо не существует процесса с данным PID, либо безопасность улучшения заставляют систему отрицать ее существование. (На В некоторых системах этот процесс может быть зомби.)

  • kill() возвращает -1, errno == EPERM

    Система не позволит вам убить указанный процесс. Это означает, что либо процесс существует (опять же, это может быть зомби) или драконовские улучшения безопасности присутствуют (например, ваш процесс не может отправлять сигналы кому-либо ).

  • kill() возвращает -1, с некоторым другим значением errno

    У вас неприятности!

Наиболее используемая техника - предполагать, что успех или неудача с EPERM подразумевает, что процесс существует, а любая другая ошибка подразумевает, что он не делает.

13 голосов
/ 01 октября 2012

Это то же самое, что и код, опубликованный Джоном Ледбеттером. Рекомендуется ссылаться на файл с именем stat в каталоге / proc / pid /, а не на cmdline, так как первый дает состояния процесса и имя процесса. Файл cmdline предоставляет полные аргументы, с которыми начинается процесс. Так что в некоторых случаях это не удается. В любом случае, идея, данная Джоном, хороша. Здесь я разместил модифицированный код Джона. Я искал код в c в Linux, чтобы проверить, работает ли 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;
}
3 голосов
/ 01 августа 2011

pidof работает, проходя по файловой системе /proc . В C вы можете сделать что-то подобное, перечислив /proc; открытие /proc/X/cmdline для каждого X, где X - список из одного или нескольких десятичных чисел. Я не знаю, есть ли у вас какие-либо требования к переносимости, но имейте это в виду, если вы полагаетесь на наличие /proc.

Эта проблема чаще всего решается в UNIX-подобных системах путем переноса запуска программы и поддержки файла PID. Смотрите /etc/init.d/* для классических примеров этого подхода. Вы должны быть осторожны, чтобы гарантировать, что код, который читает записи PID-файла, делает это безопасным способом (атомарно). Если ваша целевая ОС имеет более способную инициализацию (например, systemd ), вы можете получить эту работу оттуда.

...