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.
Determinar programáticamente si un programa se está ejecutando
franco vilea
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
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
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 0Esto 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 deerrno
¡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.
(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