Después de abrir una tubería a un proceso con popen
, ¿hay alguna manera de matar el proceso que se ha iniciado? (Utilizando pclose
no es lo que quiero porque eso esperará a que termine el proceso, pero necesito matarlo).
matar un proceso iniciado con popen
sofia alpert
slacy
no usar popen()
escriba su propia envoltura que haga lo que le gustaría.
Es bastante sencillo de fork()
y luego reemplace stdin
& stdout
mediante el uso dup2()
y luego llamando exec()
en tu hijo
De esa manera, su padre tendrá el PID del niño exacto y podrá usar
kill()
en ese.
Busque en Google “implementación popen2 ()” para obtener un código de muestra sobre cómo implementar lo que popen()
está haciendo. Solo tiene una docena de líneas más o menos. Tomado de dzone.com podemos ver un ejemplo que se ve así:
#define READ 0
#define WRITE 1
pid_t
popen2(const char *command, int *infp, int *outfp)
{
int p_stdin[2], p_stdout[2];
pid_t pid;
if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
return -1;
pid = fork();
if (pid < 0)
return pid;
else if (pid == 0)
{
close(p_stdin[WRITE]);
dup2(p_stdin[READ], READ);
close(p_stdout[READ]);
dup2(p_stdout[WRITE], WRITE);
execl("/bin/sh", "sh", "-c", command, NULL);
perror("execl");
exit(1);
}
if (infp == NULL)
close(p_stdin[WRITE]);
else
*infp = p_stdin[WRITE];
if (outfp == NULL)
close(p_stdout[READ]);
else
*outfp = p_stdout[READ];
return pid;
}
NB: parece que popen2() es lo que desea, pero mi distribución no parece venir con este método.
-
esto no resuelve el problema de la duplicación de memoria de la bifurcación. es posible que no queramos una llamada a la bifurcación por este motivo
– Voluntad
7 de enero de 2012 a las 2:03
-
@phooji, ¿qué tiene que ver Python con algo?
– Mahmud Al-Qudsi
1 de junio de 2012 a las 20:22
-
@MahmoudAl-Qudsi: Vaya. Debo haber estado mirando demasiadas preguntas de Python. [Earlier python-related comment redacted]
– phooji
2 de junio de 2012 a las 18:15
-
Lo anterior necesita “cerrar (p_stdin[READ]); close(p_stdout[WRITE]);” para evitar que dos descriptores de archivos abiertos no deseados permanezcan (lo que evita que llamadas como fgets() detecten que el hijo bifurcado ha salido).
– Chris
15 de octubre de 2012 a las 8:41
-
El código en esta respuesta tiene un problema serio: llama
exit()
siexecl()
falla Eso hará que se llame a los controladores de salida registrados por el proceso principal y que se copien los datos de flujo almacenados en búfer desde el proceso principal a los flujos que posee el proceso principal. y si elpopen2()
se llama desde un proceso de C++, también se llamará a los destructores estáticos copiados del proceso principal. El código debe llamar_exit()
en lugar deexit()
para omitir el proceso padreexit()
manipuladores–Andrew Henle
5 sep 2019 a las 11:54
Aquí hay una versión mejorada de popen2 (el crédito se debe a Sergey L.). La versión publicada por slacy no devuelve el PID del proceso creado en popen2, sino el PID asignado a sh
.
pid_t popen2(const char **command, int *infp, int *outfp)
{
int p_stdin[2], p_stdout[2];
pid_t pid;
if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
return -1;
pid = fork();
if (pid < 0)
return pid;
else if (pid == 0)
{
close(p_stdin[WRITE]);
dup2(p_stdin[READ], READ);
close(p_stdout[READ]);
dup2(p_stdout[WRITE], WRITE);
execvp(*command, command);
perror("execvp");
exit(1);
}
if (infp == NULL)
close(p_stdin[WRITE]);
else
*infp = p_stdin[WRITE];
if (outfp == NULL)
close(p_stdout[READ]);
else
*outfp = p_stdout[READ];
return pid;
}
La nueva versión debe llamarse con
char *command[] = {"program", "arg1", "arg2", ..., NULL};
-
No vi ninguna diferencia en la parte pid; ¿Puedes actualizar los comentarios sobre la diferencia?
– nayab
29 de septiembre de 2014 a las 10:53
popen en realidad no inicia un hilo, sino que bifurca un proceso. Mientras miro la definición, no parece que haya una manera fácil de obtener el PID de ese proceso y eliminarlo. Puede haber formas difíciles como examinar el árbol de procesos, pero supongo que sería mejor usar funciones de tubería, bifurcación y exec para imitar el comportamiento de popen. Luego puede usar el PID que obtiene de fork () para eliminar el proceso secundario.
En realidad, si el proceso está realizando E/S (que debería ser, de lo contrario, ¿por qué popen
en lugar de system
(3)?), entonces pclose
debería golpearlo con un SIGPIPE
la próxima vez que intente leer o escribir, debería fallar muy bien 🙂
He seguido la idea de @slacy que crea la función popen2.
Pero encontré un problema cuando el proceso secundario muere, el proceso principal aún lee el descriptor del archivo outfp
no regresa de la función.
Eso podría solucionarse agregando una canalización cerrada sin uso en el proceso principal.
close(p_stdin[READ]);
close(p_stdout[WRITE]);
Podemos obtener el pid correcto del nuevo proceso usando bash como shell.
execl("/bin/bash", "bash", "-c", command, NULL);
Cuando el proceso hijo muere, la persona que llama a la función popen2
debe recopilar el estado del proceso secundario por llamada pclose2
. si no recopilamos ese estado, el proceso secundario podría convertirse en un proceso zombi cuando finalice.
Este es el código completo que probó y funcionó como se esperaba.
#define READ 0
#define WRITE 1
pid_t
popen2(const char *command, int *infp, int *outfp)
{
int p_stdin[2], p_stdout[2];
pid_t pid;
if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
return -1;
pid = fork();
if (pid < 0)
return pid;
else if (pid == 0)
{
dup2(p_stdin[READ], STDIN_FILENO);
dup2(p_stdout[WRITE], STDOUT_FILENO);
//close unuse descriptors on child process.
close(p_stdin[READ]);
close(p_stdin[WRITE]);
close(p_stdout[READ]);
close(p_stdout[WRITE]);
//can change to any exec* function family.
execl("/bin/bash", "bash", "-c", command, NULL);
perror("execl");
exit(1);
}
// close unused descriptors on parent process.
close(p_stdin[READ]);
close(p_stdout[WRITE]);
if (infp == NULL)
close(p_stdin[WRITE]);
else
*infp = p_stdin[WRITE];
if (outfp == NULL)
close(p_stdout[READ]);
else
*outfp = p_stdout[READ];
return pid;
}
int
pclose2(pid_t pid) {
int internal_stat;
waitpid(pid, &internal_stat, 0);
return WEXITSTATUS(internal_stat);
}
-
En caso de que esto mate también todos los subprocesos bifurcados. Lo que veo es que si inicio una sesión SSH con popen2, sh llama a ssh y continúa ejecutando el proceso ssh incluso cuando se emite kill. ¿Hay alguna manera de capturar esos procesos también?
– Lonko
7 de febrero a las 9:01
andres beca
La forma obvia es system(“pkill process_name”);
Claramente, esto es problemático si tiene más de una instancia del proceso en ejecución.
-
En caso de que esto mate también todos los subprocesos bifurcados. Lo que veo es que si inicio una sesión SSH con popen2, sh llama a ssh y continúa ejecutando el proceso ssh incluso cuando se emite kill. ¿Hay alguna manera de capturar esos procesos también?
– Lonko
7 de febrero a las 9:01
pixelbeat
Hice algo similar en python, donde podía matar un subproceso y cualquier subproceso bifurcado para eso. Es similar a la solución de Slacy en realidad.
http://www.pixelbeat.org/libs/subProcess.py