saber - matar a un proceso iniciado con popen
saber el pid de un proceso windows (8)
Después de abrir una tubería para un proceso con popen
, ¿hay alguna manera de matar el proceso que se inició? (Usar pclose
no es lo que quiero porque esperará a que el proceso termine, pero tengo que matarlo).
En realidad, si el proceso está haciendo I / O (que debería ser, de lo contrario, ¿ popen
qué popen
vez de system
(3)?), Entonces, pclose
debería pclose
con un SIGPIPE
la próxima vez que intente leer o escribir, y debería caerse muy bien :-)
Hice algo similar en Python, donde puedes 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
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.
No use popen () y escriba su propio contenedor que haga lo que le gustaría.
Es bastante sencillo teclear (), y luego reemplazar stdin & stdout usando dup2 (), y luego llamar a exec () en su hijo.
De esta forma, su padre tendrá el PID infantil exacto, y puede usar kill () en eso.
Búsqueda en Google de "implementación de popen2 ()" para ver un ejemplo de código sobre cómo implementar lo que está haciendo popen (). Son solo una docena de líneas largas. 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 quieres, pero mi distribución no parece venir con este método.
popen en realidad no inicia un hilo, sino que más bien crea un proceso. Cuando miro la definición, no parece que haya una manera fácil de obtener el PID de ese proceso y matarlo. Puede haber formas difíciles como examinar el árbol de procesos, pero supongo que sería mejor utilizar las funciones de pipe, fork y exec para imitar el comportamiento de popen. Luego puede usar el PID que obtiene de fork () para matar el proceso secundario.
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 se llamará con
char *command[] = {"program", "arg1", "arg2", ..., NULL};
Tengo idea de seguir de @slacy que crea la función popen2.
Pero se encontró un problema cuando el proceso hijo se muere, el proceso principal que todavía lee el archivo descriptor outfp
no regresa de la función.
Eso podría arreglarse mediante la adición de cerrar el conducto de unuse en el proceso principal.
close(p_stdin[READ]);
close(p_stdout[WRITE]);
Podemos obtener el pid correcto de un nuevo proceso usando bash como shell.
execl("/bin/bash", "bash", "-c", command, NULL);
Cuando muere el proceso hijo, la persona que llama de la función popen2
debe recopilar el estado del proceso hijo llamando a pclose2
. si no recopilamos ese estado, el proceso hijo podría ser un proceso zombie cuando finalice.
Este es el código completo que se probó y funciona 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);
}
Simplemente puse el guión (bash), en la primera línea:
echo PID $$
luego leo el pid y lo uso para hacer a: kill (pid, 9)