Determinar programáticamente si un programa se está ejecutando

7 minutos de lectura

Determinar programaticamente si un programa se esta ejecutando
franco vilea

En C, ¿cómo puedo averiguar mediante programación si un proceso ya se está ejecutando en Linux/Ubuntu para evitar que se inicie dos veces? Estoy buscando algo similar a pidof.

  • (Tal vez podría crear un archivo de “bloqueo” temporal en una ubicación conocida al iniciar el programa, luego simplemente verifique la existencia del archivo (y elimínelo al apagarlo, aunque entonces tendrá un problema si el programa finaliza inesperadamente))

    – marnir

    1 de agosto de 2011 a las 12:24


  • @marnir: es por eso que hace que el programa escriba su propio PID en el archivo, luego, si el archivo existe, puede verificar si ese PID aún está activo y, de ser así, si el nombre del proceso coincide con el suyo. No es 100% infalible, pero aún así, las terminaciones anormales no deberían estar ocurriendo. que con frecuencia.

    – Jorge

    1 de agosto de 2011 a las 12:27

  • Si el “archivo de bloqueo” contenía el PID del programa, podría detectar una terminación anormal del programa en casi todos los casos (¿hay un proceso en ejecución con el PID que coincide con el archivo PID)? Esta no es una solución perfecta (número finito de PID, reciclaje de PID).

    – jmtd

    1 de agosto de 2011 a las 12:28

  • @marnir: si realmente bloquea el archivo de bloqueo, el bloqueo se liberará al salir del proceso. El programa simplemente intenta un bloqueo exclusivo sin bloqueo y, si falla, alguien más lo está ejecutando.

    – no pitónico

    1 de agosto de 2011 a las 12:29

  • honestamente, stackoverflow.com/questions/5460702/… parece una solución clara y fácil

    – mtk

    10/10/2015 a las 22:57

Puedes caminar por pid entradas en /proc y verifique su proceso en cualquiera de los cmdline presentar o realizar una readlink sobre el exe link (Lo siguiente usa el primer método).

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

  • Dio un espectáculo: muestra alrededor de 500 ms para ejecutar este código en cada iteración, ¿por qué lleva tanto tiempo? ¿hay mejores maneras de hacer esto?

    – GregM

    11 de abril de 2013 a las 21:06

  • Depende de la cantidad de procesos que esté ejecutando.

    – To1no

    3 de julio de 2013 a las 9:56

  • ¿Qué pasa con la eliminación de la ruta del archivo antes del nombre del programa? ¿Puedes usar comm en lugar de cmdline? Además, ¿cómo ignoras los procesos muertos?

    – gonzocerebros

    18 de noviembre de 2014 a las 20:13

  • Funcionó bien para mí. Gracias.

    – Carlos Eduardo Olivieri

    27 de agosto de 2021 a las 4:47

1647569288 580 Determinar programaticamente si un programa se esta ejecutando
yuvafácil

Este es el mismo código publicado por John Ledbetter. Es bueno consultar el archivo llamado stat en el directorio /proc/pid/ que cmdline ya que el primero proporciona los estados del proceso y el nombre del proceso. El archivo cmdline proporciona argumentos completos con los que se inicia el proceso. Entonces eso falla en algunos casos. De todos modos, la idea dada por John es buena. Aquí publiqué el código modificado de John. Estaba buscando el código en c en Linux para verificar si dhcp se está ejecutando o no. Con este código, soy capaz de hacer eso. Espero que pueda ser útil para alguien como yo.

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

  • En Android 5.1, el campo de nombre del proceso en /proc//stat tiene un límite de caracteres bastante pequeño. Solo un aviso de que algunos sistemas operativos pueden experimentar este problema similar.

    –Allen

    25 de enero de 2018 a las 20:39

1647569289 174 Determinar programaticamente si un programa se esta ejecutando
RCL

Hay formas de evitar /proc uso (y puede haber buenas razones para hacerlo, por ejemplo, /proc podría no estar instalado en absoluto, y/o podría haber sido vinculado a algo engañoso, o ese pid se ha ocultado en /proc). De acuerdo, el siguiente método no se ve tan bien, ¡ojalá hubiera una API adecuada para eso!

De todos modos, la sección 1.9 de un 1997 Preguntas frecuentes sobre la programación de Unix dice:

Utilizar kill() con 0 para el número de señal. Hay cuatro posibles resultados de esta llamada:

  • kill() devuelve 0

    Esto implica que existe un proceso con el PID dado, y el sistema le permitiría enviarle señales. Depende del sistema si el proceso podría ser un zombi.

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

    O no existe ningún proceso con el PID dado o las mejoras de seguridad están causando que el sistema niegue su existencia. (En algunos sistemas, el proceso podría ser un zombi).

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

    El sistema no le permitiría eliminar el proceso especificado. Esto significa que el proceso existe (nuevamente, podría ser un zombi) o hay mejoras de seguridad draconianas (por ejemplo, su proceso no puede enviar señales a cualquiera).

  • kill() devuelve -1, con algún otro valor de errno

    ¡Estás en problemas!

La técnica más utilizada es asumir que el éxito o el fracaso con EPERM
implica que el proceso existe, y cualquier otro error implica que no existe.

  • Después de volver a leer su pregunta… si todo lo que quiere es evitar que el proceso se ejecute dos veces, puede crear un objeto kernel con nombre (por ejemplo, un semáforo o una memoria compartida) con un nombre único y verificar su existencia al principio. . Podría ser mejor que un archivo de bloqueo, ya que desaparecerá automáticamente si su proceso falla.

    – RCL

    6 de noviembre de 2013 a las 5:49

  • Pero al usar proc no tendrá acceso a E/S de disco.

    – Kayle

    22 de noviembre de 2017 a las 9:56

  • No todos los archivos necesitan acceso al disco tampoco.

    – RCL

    8 de febrero de 2018 a las 22:20

pidof funciona caminando sobre el /proc sistema de archivos. En C, podrías hacer algo similar enumerando /proc; apertura /proc/X/cmdline para cada X donde X es una lista de uno o más números decimales. No sé si tienes algún requisito de portabilidad, pero tenlo en cuenta si vas a confiar en la disponibilidad de /proc.

Este problema se resuelve más comúnmente en sistemas similares a UNIX ajustando el inicio del programa y manteniendo un archivo PID. Ver /etc/init.d/* para ejemplos clásicos de este enfoque. Deberá tener cuidado para asegurarse de que el código que lee o escribe el archivo PID lo hace de manera segura (atómicamente). Si su sistema operativo de destino tiene un init más capaz (como sistemad), es posible que pueda externalizar este trabajo a eso.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad