Подтвердить что ты не робот

Определить программно, если программа запущена

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

4b9b3361

Ответ 1

Вы можете пройти записи 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;
}

Ответ 2

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

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

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

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

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

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

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

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

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

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

    У вас проблемы!

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

Ответ 3

Это то же самое, что и код, отправленный Джоном Ледбеттером. Хорошо ссылаться на файл с именем 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;
}

Ответ 4

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

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