Autor Tema: Cancelar un proceso en Linux con Kill desde C++  (Leído 6146 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado planeta9999

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3520
    • Pinballsp
Cancelar un proceso en Linux con Kill desde C++
« en: 26 de Febrero de 2018, 14:52:24 »
 
Buenas.

Tengo un desarrollo, desde hace tiempo, que reproduce videos en un Raspberrry. Después de mucho buscar y probar me decidí a partir de unos fuentes que tiran directo de la GPU del RPY, porque otras soluciones que probé no reproducían al instante el video.

El problema es que ese fuente, es muy críptico, casi indescifrable en cuanto a la manera de atacar a la GPU. Después de muchas pruebas, metí parte de mi código en el bucle principal que alimenta de datos a la GPU.  Funciona bastante bien, pero no puedo terminar la reproducción del video al instante o se queda colgado, me toca dejarle al menos un par de segundos y ese tiempo no siempre es igual para todos los videos, depende del tamaño del video.

Hoy, mirando cosas por Google, me he encontrado unos fuentes en Python que usan otra táctica, que me ha parecido interesante. El programa que reproduce el video es independiente y no está modificado, lo que hacen es llamar a ese programa externo desde el programa principal, y cuando lo quieren cancelar lanzan un "kill -9" más el PID del programa para matar el proceso.

Mi duda es de donde sacan el PID del proceso, a mi me vendría muy bien usar la misma técnica, si funciona, pero lo haría desde C++. Lanzo el video con una llamada a ese programa y cuando lo quiera parar (normalmente porque quiero reproducir otro video antes de que ese acabe), le hago un Kill al proceso.

Estos son parte de los fuentes en Python. ¿ Sabeis de donde está saliendo el PID del proceso al que luego se le aplica el KILL -9 ?.


Bucle del programa principal:

    def run(self):
        """Main program loop.  Will never return!"""
        # Get playlist of movies to play from file reader.
        playlist = self._build_playlist()
        self._prepare_to_run_playlist(playlist)
        # Main loop to play videos in the playlist and listen for file changes.
        while self._running:
            # Load and play a new movie if nothing is playing.
            if not self._player.is_playing():
                movie = playlist.get_next()
                if movie is not None:
                    # Start playing the first available movie.
                    self._print('Playing movie: {0}'.format(movie))
                    self._player.play(movie, loop=playlist.length() == 1, vol = self._sound_vol)
            # Check for changes in the file search path (like USB drives added)
            # and rebuild the playlist.

            if self._reader.is_changed():
                self._player.stop(3)  # Up to 3 second delay waiting for old
                                      # player to stop.
                # Rebuild playlist and show countdown again (if OSD enabled).
                playlist = self._build_playlist()
                self._prepare_to_run_playlist(playlist)
            # Give the CPU some time to do other tasks.
            time.sleep(0.002)



Rutina, en la que se mata el proceso con un Kill -9:

    def stop(self, block_timeout_sec=None):
        """Stop the video player.  block_timeout_sec is how many seconds to
        block waiting for the player to stop before moving on.
        """
        # Stop the player if it's running.
        if self._process is not None and self._process.returncode is None:
            # process.kill() doesn't seem to work reliably if USB drive is
            # removed, instead just run a kill -9 on it.

            subprocess.call(['kill', '-9', str(self._process.pid)])
        # If a blocking timeout was specified, wait up to that amount of time
        # for the process to stop.

        start = time.time()
        while self._process is not None and self._process.returncode is None:
            if (time.time() - start) >= block_timeout_sec:
                break
            time.sleep(0)
        # Let the process be garbage collected.
        self._process = None
« Última modificación: 26 de Febrero de 2018, 15:04:07 por planeta9999 »

Desconectado tsk

  • PIC18
  • ****
  • Mensajes: 255
Re:Cancelar un proceso en Linux con Kill desde C++
« Respuesta #1 en: 26 de Febrero de 2018, 15:37:02 »
¿De donde obtiene el PID?

Para el PID propio os.getpid()

Si estas ejecutando un comando con subprocess

Código: Python
  1. p = subprocess.Popen("ls");
  2. print(p.pid)

y lo que ves como self._process me imagino que en otra parte del códgo le esta haciendo algo como

Código: Python
  1. self._process = subprocess.Popen("comando")

Así tienes acceso a su PID con

Código: Python
  1. self._process.pid

Si quieres obtener el PID de otros procesos en python se puede hacer uso de psutil, donde incluso puedes obtener el estado de cada proceso así como los procesos hijos de este.

Te dejo un ejemplo completo

Código: Python
  1. import os
  2. import psutil
  3.  
  4. print(os.getpid())
  5.  
  6. print("...............")
  7. import subprocess
  8.  
  9. p = subprocess.Popen("ls");
  10. print(p.pid)
  11.  
  12. print("....................")
  13.  
  14. for p in psutil.process_iter():
  15.     if p.name() == "python":
  16.         print(p)
  17.         print(p.cmdline())
  18.         print(p.get_memory_info())
  19.         print(p.status())
  20.         print(p.get_children())

Desconectado planeta9999

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3520
    • Pinballsp
Re:Cancelar un proceso en Linux con Kill desde C++
« Respuesta #2 en: 26 de Febrero de 2018, 15:56:33 »
Gracias tsk, si en efecto en otra rutina aparece el popen, precisamente en la que manda a reproducir el video que luego para con el kill.

    def play(self, movie, loop=False, **kwargs):
        """Play the provided movied file, optionally looping it repeatedly."""
        self.stop(3)  # Up to 3 second delay to let the old player stop.
        # Assemble list of arguments.
        args = ['hello_video.bin']
        if loop:
            args.append('--loop')         # Add loop parameter if necessary.
        args.append(movie)                # Add movie file path.
        # Run hello_video process and direct standard output to /dev/null.
        self._process = subprocess.Popen(args,
                                         stdout=open(os.devnull, 'wb'),
                                         close_fds=True)


No obstante, mi idea es hacer lo mismo pero desde C++. Desde un programa llamar a otro y poder pararlo en cualquier momento, supongo que con un Kill.

Buscando por Google, me encuentro con la llamada al programa usando fork() y exec(), no veo aún como se conoce el PID del proceso llamado desde un programa en C++ para luego eliminarlo con kill.

Creo que podría ser así en C, pero no estoy seguro:

pid_t PID = fork();
 if(PID == 0) {
      execl("yourcommandhere");
      exit(1);
 }
 //do Whatever
 kill(PID, 15);  //Sends the SIGINT Signal to the process, telling it to stop.



o tal vez así:

when you executed with system(./mjpg_streamer)

A user process mjpg_streamer is created

You can kill this process again with pkill(mjpg_streamer)
« Última modificación: 26 de Febrero de 2018, 16:04:35 por planeta9999 »

Desconectado tsk

  • PIC18
  • ****
  • Mensajes: 255
Re:Cancelar un proceso en Linux con Kill desde C++
« Respuesta #3 en: 26 de Febrero de 2018, 16:11:55 »
En C++ lo acabo de probar de la siguiente forma

Código: C
  1. #include <iostream>
  2. using namespace std;
  3.  #include <cstdlib>
  4.  
  5. #include <sys/types.h>
  6. #include <signal.h>
  7. #include <unistd.h>
  8.  
  9. int main()
  10. {
  11. int process;
  12.  
  13. if ((process = fork()) < 0) {
  14.     cout << "Error\n";
  15. }
  16. else if (process == 0) {
  17.     cout<<"Proceso Hijo PID: "<<getpid()<<endl;
  18.                 setpgid(getpid(),getpid());
  19.     system("python main.py");
  20. }
  21. else {
  22.                 sleep(10);
  23.     kill(-process, SIGKILL);
  24.                 cout<<"Processo Padre comete Filicidio\n";
  25. }
  26.  
  27. return 0;
  28.  
  29. }

Código: Python
  1. from time import sleep
  2.  
  3. while(1):
  4.     print("Hola mundo\n");
  5.     sleep(1);

Código: [Seleccionar]
$ ./a.out
Proceso Hijo PID: 23889
Hola mundo

Hola mundo

Hola mundo

Hola mundo

Hola mundo

Hola mundo

Hola mundo

Hola mundo

Hola mundo

Hola mundo

Processo Padre comete Filicidio

Desconectado planeta9999

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3520
    • Pinballsp
Re:Cancelar un proceso en Linux con Kill desde C++
« Respuesta #4 en: 26 de Febrero de 2018, 16:27:02 »

Gracias, voy a probarlo todo.
Tengo algunas dudas:

1.- ¿ El fork() devuelve siempre el PID del último proceso llamado desde el programa principal ?
2.- ¿ Si cuando vamos a hacer el Kill, el proceso ya terminó por si solo, que pasaría, el Kill podría dar error o terminar con otro proceso ?

También por lo que leo, se podría terminar un programa usando Pkill para cancelarlo por su nombre, sin necesidad de saber el PID.

La idea es terminar un proceso lanzado desde el programa principal en C++, pero comprobando antes si ese proceso todavía está en ejecución, en caso de que usando kill de problemas si el proceso a matar ya no está en ejecución. O tal vez usar Pkill para matar un programa por su nombre sin conocer el PID.

Desconectado AcoranTf

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1093
Re:Cancelar un proceso en Linux con Kill desde C++
« Respuesta #5 en: 26 de Febrero de 2018, 16:34:46 »
Por si te sirve de algo, yo utilizo el comando kill para "matar" el firefox cuando alguna pagina de esas chungas me abre ventanas sin opcion de cerrar.
Para ello tengo un "lanzador" que lo unico que hace es ejecutar el comando: pkill firefox.
Te dejo info sobre las posibilidades de kill y como obtener en consola el listado de procesos en ejecucion, con su correspondiente PID.

Código: [Seleccionar]
Para listar procesos en ejecucion:    ps -A

Para matar un proceso:                kill -9 PID      (PID es el identificador del proceso)

Otro metodo:                          pkill firefox    (Mata directamente sin necesidad del PID)

Otro metodo:                          killall firefox  (Mata todos los procesos de la aplicacion)

Saludos.

Desconectado planeta9999

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3520
    • Pinballsp
Re:Cancelar un proceso en Linux con Kill desde C++
« Respuesta #6 en: 26 de Febrero de 2018, 16:42:56 »
Gracias AcoranTf.

Suponiendo que el programa a matar se llame "video_player", entiendo que desde mi programa en C++, podría hacer algo así, para acabar con ese proceso:

system("pkill video_player");

¿ Sería la forma más sencilla de matar un proceso desde C++ ?. No se si hace falta comprobar antes que el proceso todavía existe, o eso da igual. ¿ Es instantáneo o le cuesta ?. Creo que lo mejor será poner en marcha el Raspberry, y empezar a probar.

Supongo, aunque no lo he probado, que si en vez de matar al proceso video_player, lo vuelvo a llamar, la nueva llamada no reemplazará a la anterior, sino que se ejecutará dos veces y se armará lío o se bloqueará porque ambos sacan video directo a la GPU del Raspberry.

También tengo la duda de si para ejecutar el programa externo "Video_player" desde C++, tengo que usar system () o execlp(). O si el system() es solo para ejecutar comandos de sistema y el execlp() para lanzar programas propios.

#include <stdlib.h>
   //Console command:
   system("cp file.x newfile.x");

   //Execute file:
   execlp("/usr/bin/omxplayer", " ", "/home/pi/projects/game/audio/alpha.wav", NULL);   
   
« Última modificación: 26 de Febrero de 2018, 16:52:32 por planeta9999 »

Desconectado tsk

  • PIC18
  • ****
  • Mensajes: 255
Re:Cancelar un proceso en Linux con Kill desde C++
« Respuesta #7 en: 26 de Febrero de 2018, 16:49:28 »
De hecho fork no devuelve el PID, devuelve -1 en caso de error y 0 en caso de exito.

con getpid() obtienes el PID del proceso en el que te encuentras.

la función kill retorna 0 cuando tuvo exito o -1 cuando fallo.

Código: C
  1. #include <iostream>
  2. using namespace std;
  3.  #include <cstdlib>
  4.  
  5. #include <sys/types.h>
  6. #include <signal.h>
  7. #include <unistd.h>
  8.  
  9. int main()
  10. {
  11. int process;
  12.  
  13. if ((process = fork()) < 0) {
  14.     cout << "Error\n";
  15. }
  16. else if (process == 0) {
  17.     cout<<"Proceso Hijo PID: "<<getpid()<<endl;
  18.                 setpgid(getpid(),getpid());
  19.     system("python main.py");
  20. }
  21. else {
  22.                 cout << "Proceso Padre PID: " << getpid()<<endl;
  23.                 sleep(10);
  24.     kill(-process, SIGKILL);
  25.                 cout<<"Processo Padre comete Filicidio\n";
  26. }
  27.  
  28. return 0;
  29.  
  30. }

Código: [Seleccionar]
$ ./a.out
Proceso Padre PID: 24397
Proceso Hijo PID: 24398
Hola mundo

Hola mundo

Hola mundo

Hola mundo

Hola mundo

Hola mundo

Hola mundo

Hola mundo

Hola mundo

Hola mundo

Processo Padre comete Filicidio

Si lo llamas varias veces, simplemente el la condición if de cada fork ejecutas un getpid() para obtener el PID de dicho proceso y en lugar de tener process, tendrías process1, process2, process3, etc. o un arreglo

Es dificil que mates otro proceso, ya que los números son incrementales, por lo que un número ya dado no se va a volver a repetir.


Hay otra función que se llama wait y con ella pones al proceso padre a esperar que termine el hijo.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Cancelar un proceso en Linux con Kill desde C++
« Respuesta #8 en: 26 de Febrero de 2018, 16:51:50 »
El dilema es que... tal ves el esta buscando crear un thread y no un fork.
O el intenta eliminar un PID que se lanzo desde C++ pero ejecutando python

Desconectado AcoranTf

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1093
Re:Cancelar un proceso en Linux con Kill desde C++
« Respuesta #9 en: 26 de Febrero de 2018, 16:55:00 »
El efecto es instantaneo y si no existe no hay problema, al menos en consola y mediante lanzador no devuelve ningun error.
Si tienes varios procesos de la misma aplicacion el comando kill, los mata en orden inverso de creacion, o sea primero mata al ultimo.
Si tienes un proceso en ejcucion de una aplicacion y la llamas de nuevo, se crea otro proceso.
En cualquier caso no olvides que tienes el comando: killall.

Saludos.

Desconectado planeta9999

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3520
    • Pinballsp
Re:Cancelar un proceso en Linux con Kill desde C++
« Respuesta #10 en: 26 de Febrero de 2018, 17:05:32 »
 
Vale perfecto, gracias, lo voy probar.

Esto de los fork y los thread, no lo cazo, y creo que no es exactamente lo que busco o no lo he entendido. Creo que un fork lanza una copia idéntica del programa actual, y eso no es lo que quiero hacer.

La idea es desde un programa en C++ lanzar otro programa que reproduce un video, y en un momento determinado, en base a señales externas que me entran por un GPIO, puedo necesitar lanzar otro video, pero parando el actual si todavía está reproduciéndose.

Creo que algo así me podría servir, lo tengo que probar:

// Ejecuta programa video_player, desde C++,, pasándole parámetros:
   execlp("/usr/bin/video_player", " ", "/home/pi/projects/game/audio/alpha.wav", NULL);   

// Mata el proceso anterior
   system("pkill video_player");

O tal vez, el programa "video_player" también se puede lanzar usando system(), no entiendo muy bien todavía la diferencia entre usar system(), exec() y execlp() para llamar a un programa externo.

system ("/usr/bin/video_player  /home/pi/projects/game/audio/alpha.wav")

 
« Última modificación: 26 de Febrero de 2018, 17:15:11 por planeta9999 »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Cancelar un proceso en Linux con Kill desde C++
« Respuesta #11 en: 26 de Febrero de 2018, 17:10:38 »
Citar
La idea es desde un programa en C++ lanzar otro programa que reproduce un video, y en un momento determinado, en base a señales externas que me entran por un GPIO, puedo necesitar lanzar otro video, pero parando el actual si todavía está reproduciéndose.

Tal ves seria mejor si explicas como lo inicias a ese video, si ejecutas desde C++ una linea de comando, o lo haces directamente desde C++, etc. Ya que el codigo es de python el que pasaste.

Podrias tratar de buscar el PID respecto al nombre del proceso, hay funciones por internet que lo hacen. Luego teniendo el PID procedes a matarlo.
Lo que si tenes que asegurarte que no este abierto mas de una ves.
« Última modificación: 26 de Febrero de 2018, 17:13:47 por KILLERJC »

Desconectado planeta9999

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3520
    • Pinballsp
Re:Cancelar un proceso en Linux con Kill desde C++
« Respuesta #12 en: 26 de Febrero de 2018, 17:19:21 »
Citar
La idea es desde un programa en C++ lanzar otro programa que reproduce un video, y en un momento determinado, en base a señales externas que me entran por un GPIO, puedo necesitar lanzar otro video, pero parando el actual si todavía está reproduciéndose.

Tal ves seria mejor si explicas como lo inicias a ese video, si ejecutas desde C++ una linea de comando, o lo haces directamente desde C++, etc. Ya que el codigo es de python el que pasaste.

Ahora mismo lo tengo hecho, tocando directamente el fuente que trabaja con la GPU del Raspberry para reproducir un video, es un programa en C++. Eso es lo que quiero cambiar, dejar ese programa independiente (llamémosle video_player), al que llamaría desde otro programa en C++ (programa principal), pasándole como parámetro el video a reproducir.

El código que puse de Python, me dio ideas para hacerlo de otra manera, en el sentido de usar el Kill para parar ese reproductor de video que lanzaría desde mi programa principal en C++, pero eso no lo tengo hecho todavía.

Citar
Podrias tratar de buscar el PID respecto al nombre del proceso, hay funciones por internet que lo hacen. Luego teniendo el PID procedes a matarlo.
Lo que si tenes que asegurarte que no este abierto mas de una ves.

Si el Pkill me funciona con el nombre de programa como parámetro, ya me vale, y no me complico la vida buscando el PID del proceso que lancé.

« Última modificación: 26 de Febrero de 2018, 17:25:57 por planeta9999 »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Cancelar un proceso en Linux con Kill desde C++
« Respuesta #13 en: 26 de Febrero de 2018, 18:45:02 »
Entonces tal ves el fork te pueda servir. Lo que si vas a tener que diferencia luego del fork cual es tu proceso padre e hijo. Asi como lo hizo tsk

https://stackoverflow.com/questions/13557853/how-to-start-a-executable-within-a-c-program-and-get-its-process-id-in-linux

Desconectado planeta9999

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3520
    • Pinballsp
Re:Cancelar un proceso en Linux con Kill desde C++
« Respuesta #14 en: 26 de Febrero de 2018, 19:12:14 »
Entonces tal ves el fork te pueda servir. Lo que si vas a tener que diferencia luego del fork cual es tu proceso padre e hijo. Asi como lo hizo tsk

https://stackoverflow.com/questions/13557853/how-to-start-a-executable-within-a-c-program-and-get-its-process-id-in-linux


Lo probaré de las dos maneras.

La ventaja que le veo a usar el Pkill es que no es necesario averiguar el PID del proceso a matar, lo hace por nombre de programa, y como ese nombre de programa solo se estará ejecutando una vez, no hay problema.