TODOPIC

Misceláneas - Interés General => Off Topic => Mensaje iniciado por: planeta9999 en 26 de Febrero de 2018, 14:52:24

Título: Cancelar un proceso en Linux con Kill desde C++
Publicado por: planeta9999 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
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: tsk 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())
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: planeta9999 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)
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: tsk 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
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: planeta9999 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.
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: AcoranTf 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.
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: planeta9999 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);      
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: tsk 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.
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: KILLERJC 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
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: AcoranTf 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.
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: planeta9999 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")

 
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: KILLERJC 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.
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: planeta9999 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é.

Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: KILLERJC 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
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: planeta9999 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.
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: planeta9999 en 26 de Febrero de 2018, 22:34:52
 

Sigo leyendo cosas, y mi duda es que comando usar para llamar al programa externo desde C++. Parece que hay tres formas de hacerlo.

1.- system
2.- popen
3.- fork + exec

Tendré que conectar el Raspberry y probarlo todo, es un proyecto que lo tenía medio dormido y ya toca retomarlo, pero ahora con una solución más racional.

Me ha parecido que incluso podría lanzar la reproducción de los videos en ventanas, o poder mezclar la reproducción de un video con texto.
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: KILLERJC en 26 de Febrero de 2018, 22:43:49
Tal ves esto te ayude a decidirte:

https://stackoverflow.com/questions/8538324/what-is-the-difference-between-popen-and-system-in-c
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: Geo en 27 de Febrero de 2018, 05:38:23


Sigo leyendo cosas, y mi duda es que comando usar para llamar al programa externo desde C++. Parece que hay tres formas de hacerlo.

1.- system
2.- popen
3.- fork + exec

Tendré que conectar el Raspberry y probarlo todo, es un proyecto que lo tenía medio dormido y ya toca retomarlo, pero ahora con una solución más racional.

Me ha parecido que incluso podría lanzar la reproducción de los videos en ventanas, o poder mezclar la reproducción de un video con texto.
Lo que entiendo es que quieres es cerrar una aplicación que está corriendo en el sistema pero no te importa tener mayor control sobre ella. Para ello basta lo que ya AcoranTf mencionó, pkill o killall te permiten matar todos los procesos con el nombre que indiques, así tengas una, dos o más instancias del mismo proceso con esos comandos cerrarás todas.

¿Cómo llamarlos desde tu aplicación? Basta con algo como:
Código: C
  1. system("pkill nombre_proceso");
  2. system("killall nombre_proceso");

Ahora, la función system() devuelve un entero que, generalmente, corresponde al código de salida (https://www.gnu.org/software/libc/manual/html_node/Exit-Status.html) devuelto por el comando que ejecutaste (en este caso sería lo que devuelva pkill/killall), por lo que también podrías hacer algo como esto para tener alguna noción de qué resultó de tu llamada a pkill/killall:
Código: C
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. int main(int argc, char* argv[]) {
  5.     if (system("killall programa") == 0) {
  6.         printf("programa estaba en ejecución, se cerró.");
  7.     }
  8.     else {
  9.         printf("programa no está en ejecución.");
  10.     }
  11.  
  12.     return 0;
  13. }

Los valores que devuelve system generalmente corresponden a lo que devolvió el programa al terminar (p. ej. el return 0; al final del programa de ejemplo).

En cuanto a popen, te sería útil en caso de que quieras mayor control sobre las aplicaciones externas que estás ejecutando desde tu programa, por ejemplo, si la aplicación externa te devuelve algún texto en cierto formato, para recibir dicho texto puedes utilizar popen (system solamente devuelve un número). Para una aplicación que hice hace ya varios años utilizo precisamente esta opción para comunicarme con un reproductor de videos y obtener algunos datos que el reproductor proporciona (tiempo de avance de la reproducción, p. ej.).

Un ejemplo llamando a mkdir:
Código: C
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. int main(int argc, char* argv[]) {
  5.     if (system("mkdir dirtest") == 0) {
  6.         printf("Se creó dirtest");
  7.     }
  8.     else {
  9.         printf("No se creó dirtest.");
  10.     }
  11.  
  12.     return 0;
  13. }

Si no existe el directorio dirtest, la primera vez que ejecutas este programa, la salida sería esta:
$ ./creadirtest
Se creó dirtest


Pero si lo ejecutas una segunda vez (con el directorio ya creado):
$ ./creadirtest
mkdir: cannot create directory ‘dirtest’: File exists
No se creó dirtest.


Puedes observar que la salida de mkdir se mezcló con la de nuestro programa. Desde nuestro programa solamente sabemos que no obtuvimos una salida en 0, por lo que imprimimos que no se creó el directorio, pero no tenemos acceso al texto de salida de mkdir (mkdir: cannot create directory ‘dirtest’: File exists), para poderlo obtener en tu código tendrías que hacer uso de popen, aunque creo que no lo necesitas para lo que has comentado.
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: planeta9999 en 27 de Febrero de 2018, 08:43:57
Lo que entiendo es que quieres es cerrar una aplicación que está corriendo en el sistema pero no te importa tener mayor control sobre ella. Para ello basta lo que ya AcoranTf mencionó, pkill o killall te permiten matar todos los procesos con el nombre que indiques, así tengas una, dos o más instancias del mismo proceso con esos comandos cerrarás todas.


Lo que he leído es que system es la menos segura de las tres opciones, y fork-exec* la mejor en ese sentido.

No es solo para lanzar el pkill, también para lanzar el programa que reproduce el video con el parámetro del video a reproducir. En principio no necesito control sobre la reproducción del video, solo arrancarlo y cancelarlo para reproducir otro.

Lo mejor será probarlo todo en el Raspberry, a ver que ventajas tiene cada uno.
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: KILLERJC en 27 de Febrero de 2018, 11:16:01
no te va a preocupar lo seguro a vos. Al menos si la unica forma de entrar al sistema es atraves de una SD.. Lo que si con system() vas a tener para mi un pequeño problema, ya Geo te lo dijo pero no tan directamente:


Citar
Ahora, la función system() devuelve un entero que, generalmente, corresponde al código de salida devuelto por el comando que ejecutaste (

Es decir la funcion system es bloqueante, y unicamente va a avanzar de alli luego de que esta salga o se detenga. Esto quiere decir que en el mismo programa no vas a poder iniciar y detener el proceso.

Por otro lado la opcion de fork+exec si no mal lei el PID de aquello ejecutado por el exec es el el mismo devuelto por el fork, por lo tanto es mas simple para vos.

tiras un fork. si es padre solamente lees las entradas  procedes a matar (Usando el PID que te dio el fork) o esperar el proceso hijo que termine.
en el proceso hijo ejecutas el video que deseas.

Un ejemplo mas grafico:
https://stackoverflow.com/questions/4204915/please-explain-the-exec-function-and-its-family
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: planeta9999 en 27 de Febrero de 2018, 11:29:00

Es decir la funcion system es bloqueante, y unicamente va a avanzar de alli luego de que esta salga o se detenga. Esto quiere decir que en el mismo programa no vas a poder iniciar y detener el proceso.


Entonces no me vale para lanzar el video, solo para cancelarlo con pkill.

Cuando lanzo el video, el programa principal tiene que seguir funcionando mientras se reproduce el video. En este programa se chequean el estado de una matriz de señales que leo con varios expansores de puertos MCP23s17, y según esas señales se lanzan nuevos videos, siempre cancelando antes el que pueda estar ejecutándose.

Lo de fork-exec*, no lo entiendo muy bien todavía. Parece que el fork duplica el programa actual, osea mi programa principal, algo yo no necesito, y el exec sería el que realmente lanzaría el nuevo programa, el reproductor de video.

¿ Entonces puedo hacer un exec desde el programa principal para lanzar el reproductor de video, o es neceario el fork también ?.


Vaya lío, a ver si voy cazando conceptos:

1.- system: ejecuta un programa externo al principal, pero no deja seguir al programa principal hasta que acabe el programa llamado. No me vale para lanzar el reproductor de video, pero si para el pkill.

2.- Fork-exec*:  fork crea un duplicado del programa actual (el principal), y desde ambos (original y copia) se puede detectar si estás en el programa padre o en el hijo, si estás en el programa hijo, con un exec* lanzaría el reproductor de video. En cualquier caso, el programa principal sigue su curso independiente del programa externo a llamar. Me vale para lanzar el reproductor de video, pero creo que no sería una buena elección para lanzar el pkill, porque el programa principal no debe de lanzar un nuevo video hasta que se cancele el que está en curso.

3.- Popen: no se todavía como funciona. Y este es el que han utilizado en los fuentes de ejemplo en Python que he puesto, que hacen algo parecido a lo que yo quiero hacer.


exec replaces the current process with another one.
system runs another program, wait for its completion.
fork copies the current process; both the original and the copy continue from the same point.
pipe sets up a pipe between two handles.
syscall makes a low-level system call.
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: Geo en 27 de Febrero de 2018, 12:35:03
system si es bloqueante, pero puedes agregar el operador & al comando que quieres ejecutar para que corra en "background". Considero que system es más que suficiente si solo requieres iniciar/detener una aplicación.

Código: C
  1. system("killall programa &");

¿El reproductor que pretendes iniciar/cerrar es una aplicación propia o algún reproductor ya existente?
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: tsk en 27 de Febrero de 2018, 14:50:51
No veo cual es el problema, aunque system bloquee, no bloquea el programa principal. En el siguiente ejemplo inicio y detengo vlc en varias ocasiones.  Aunque no es el mejor ejemplo con lo que respecta a un buen programa, y mucho menos está terminado, pero te da idea de una de las formas en que se puede hacer.

Código: C
  1. #include <iostream>
  2. using namespace std;
  3.  #include <cstdlib>
  4.  
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. #include <signal.h>
  8. #include <unistd.h>
  9.  
  10. int pid = -1;
  11.  
  12. static void fork_process(char *cmd)
  13. {
  14.         int process;
  15.         process = fork();
  16.         switch(process)
  17.         {
  18.                 case -1:
  19.                         cout << "Error" << endl;
  20.                         break;
  21.                 case 0:
  22.                         pid = process;
  23.                         setpgid(getpid(),getpid());
  24.                         system(cmd);  //Si termina la ejecución se le puede agregar algo para que se espere
  25.                                               //como un while(1){} para esperar a que el Proceso padre lo mate
  26.                         break;
  27.                 default:
  28.                         cout << "Master Created subprocess" << endl;
  29.                         cout << process << endl;
  30.                         pid = process;
  31.                         break;
  32.         }
  33.  
  34. }
  35.  
  36.  
  37. int main()
  38. {
  39.                 int gpid, user_response;
  40.                 signal(SIGCHLD, SIG_IGN); //Para evitar Zombies
  41.                 gpid = getpid();
  42.                 cout << gpid << endl;
  43.                 //cout << "0 - Iniciar VLC\n1-Detener VLC\n";
  44.                 while(1)
  45.                 {
  46.                         cout << "0 - Iniciar VLC\n1-Detener VLC\n";
  47.                         cin >> user_response;
  48.                         switch(user_response)
  49.                         {
  50.                                 case 0:
  51.                                         fork_process("vlc");
  52.                                         cout << "----------------"<< endl;
  53.                                         cout << getpid() << endl;
  54.                                         cout << pid << endl;
  55.                                   cout << gpid << endl;
  56.                                         break;
  57.                                 case 1:
  58.                                         cout << "Killing Process " << pid << endl;
  59.                                         kill(-pid, SIGKILL);
  60.                                         break;
  61.                                 default:
  62.                                         break;
  63.  
  64.                         }
  65.                 }
  66.                
  67.         return 0;
  68.  
  69. }

Código: [Seleccionar]
$ ./a.out
4755
0 - Iniciar VLC
1-Detener VLC
0
Master Created subprocess
4756
----------------
4755
4756
4755
0 - Iniciar VLC
1-Detener VLC
VLC media player 2.1.6 Rincewind (revision 2.1.6-0-gea01d28)
[0x6f9118] main libvlc: Ejecutar vlc con la interfaz predeterminada. Use «cvlc» para usar vlc sin interfaz.
1
Killing Process 4756
0 - Iniciar VLC
1-Detener VLC
1
Killing Process 4756
0 - Iniciar VLC
1-Detener VLC
0
Master Created subprocess
4765
----------------
4755
4765
4755
0 - Iniciar VLC
1-Detener VLC
VLC media player 2.1.6 Rincewind (revision 2.1.6-0-gea01d28)
[0x745118] main libvlc: Ejecutar vlc con la interfaz predeterminada. Use «cvlc» para usar vlc sin interfaz.
1
Killing Process 4765
0 - Iniciar VLC
1-Detener VLC
^C

Otra es que separes los dos programas y los comuniques por medio de sockets o tuberías, además también podrías también hacer uso de librerías como libevent o libuv
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: planeta9999 en 27 de Febrero de 2018, 19:28:35
system si es bloqueante, pero puedes agregar el operador & al comando que quieres ejecutar para que corra en "background". Considero que system es más que suficiente si solo requieres iniciar/detener una aplicación.

Código: C
  1. system("killall programa &");

¿El reproductor que pretendes iniciar/cerrar es una aplicación propia o algún reproductor ya existente?

El reproductor de video es un programa mío en C++. Cuando lo lance, el programa principal debe de seguir funcionando, no puede quedar bloqueado hasta que termine el reproductor de video.

Probaré lo del &.
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: planeta9999 en 27 de Febrero de 2018, 19:31:09
No veo cual es el problema, aunque system bloquee, no bloquea el programa principal. v


No entiendo esto. ¿ que es lo que bloquea system ?, ¿ si lanzo un programa con system, el programa principal sigue funcionando aunque no haya terminado el programa llamado ?.

El programa principal debe de seguir su curso, no se puede quedar parado hasta que termine el programa llamado (reproductor de video), eso no me serviría.
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: KILLERJC en 27 de Febrero de 2018, 19:43:07
No entiendo esto. ¿ que es lo que bloquea system ?, ¿ si lanzo un programa con system, el programa principal sigue funcionando aunque no haya terminado el programa llamado ?.

El programa principal debe de seguir su curso, no se puede quedar parado hasta que termine el programa llamado (reproductor de video), eso no me serviría.

Por eso mismo usa el fork. Para que el child se bloquee con el system, mientras que el parent sigue su curso.
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: tsk en 27 de Febrero de 2018, 20:19:17
El fork hace una copia del programa y lo pone en otro proceso hijo, por lo que tendrías dos programas similares corriendo en paralelo, así que aunque system o cualquier otro bloquee, este no va a producir ningún efecto en el flujo del programa padre.

Código: [Seleccionar]
Padre    Hijo
''
''
''fork()
''==========
''        ''
''        ''
''        ''
''        ''
''        ''
''        ''
''        ''
''        ''
V         V

En el ejemplo que te mostré, es lo que hace, el proceso Padre puede crear y matar a su hijo a placer. El proceso Hijo la única función que tiene es la de ejecutar VLC, mientras el padre se dedica a otras cosas.

Aquí un video para que lo veas en acción


El estado cuando se inicia el programa (./a.out)

(https://i.imgur.com/QJwHFDt.png)

El estado cuando el padre crea al hijo y el hijo ejecuta el vlc a través de system. Se pueden ver dos procesos llamados ./a.out más los procesos específicos del reproductor multimedia VLC.

(https://i.imgur.com/YfB4lSe.png)

Cuando el padre mata a su hijo de nueva cuenta regresa al estado como el que se muestra en la primera imagen
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: tsk en 27 de Febrero de 2018, 20:55:07
El reproductor de video es un programa mío en C++. Cuando lo lance, el programa principal debe de seguir funcionando, no puede quedar bloqueado hasta que termine el reproductor de video.

Ya que es tuyo el programa, entonces te convendría ver la posibilidad de sobrescribir los manejadores de señales e incorporarlos en tu diseño.

Si haces un kill -l vas a ver las señales que pueden recibir cualquier proceso

Código: [Seleccionar]
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX

Las que conocemos principalmente son SIGINT (cuando presionamos Ctrl+C), SIGKILL, SIGTERM, e incluso están los SIGUSR1 y SIGUSR2 que son definidos por el usuarios. Pero podemos sobre escribir la acción, de la siguiente forma.

Código: C
  1. #include <iostream>
  2. using namespace std;
  3. #include <cstdlib>
  4. //#include <csignal>
  5.  
  6. #include <sys/types.h>
  7. #include <sys/wait.h>
  8. #include <signal.h>
  9. #include <unistd.h>
  10.  
  11. void custom_signal_handler(int signum)
  12. {
  13.         cout << "Acabas de presionar Ctrl+C, entonces Adios" << endl;
  14.         exit(0);
  15. }
  16.  
  17. int main()
  18. {
  19.         //Asignamos nuestra propia funcion para terminar el proceso a la
  20.         //hora de recibir un Ctrl+C
  21.         signal(SIGINT,custom_signal_handler);
  22.  
  23.         cout << "Presiona Ctrl+C para terminar el programa" << endl;
  24.         while(1)
  25.         {}
  26.  
  27.         return 0;
  28. }

Y su salida

Código: [Seleccionar]
$ ./signals
Presiona Ctrl+C para terminar el programa
^CAcabas de presionar Ctrl+C, entonces Adios

De igual forma si nos sabemos su PID, podemos mandarle la señal SIGNT por medio del comando kill (kill -2 PID) o a través de otro programa en C/C++

(https://i.imgur.com/g8DB7DG.png)

Así que puedes reescribir los manejadores para algunos de las señales (SIGUSR1, SIGUSR2) para que detenga la ejecución del video para que le de la oportunidad de leer algún valor que otro programa le envíe a través de una tubería para que cambie de video o que simplemente detenga la ejecución del mismo.

Por lo tanto puedes tener dos programas totalmente independientes, simplemente el programa que verifica el estado de las entradas le va a enviar las señales adecuadas al proceso del reproductor de vídeo, para que se detenga unos momentos a leer algo que le estas enviando, así te evitas el dichoso fork() y al no tener que cerrarse el reproductor de video podrías pensar en realizar transiciones más complejas(entre videos) de lo que podrías hacer con sólo cerrar y abrir de nuevo la aplicación.

------
Añado que aparentemente puedes enviar datos usando sigqueue. Nunca lo había visto pero podrías ser también prometedor

http://man7.org/linux/man-pages/man3/sigqueue.3.html
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: planeta9999 en 28 de Febrero de 2018, 12:38:16
El fork hace una copia del programa y lo pone en otro proceso hijo, por lo que tendrías dos programas similares corriendo en paralelo, así que aunque system o cualquier otro bloquee, este no va a producir ningún efecto en el flujo del programa padre.


Me refería a un system desde el programa principal, sin hacer un fork, eso es lo que entendí que bloquearía el programa principal hasta que termine el programa llamado.


Otra técnica que he leído es crear un pipe, creo que es un canal de comunicación entre el programa principal y el llamado, desconozco si bidireccional o en un solo sentido.

Por ejemplo usando el video reproductor omxplayer, sería así.

1. Create fifo file ( i.e. mkfifo /dev/shm/buffer.fifo )
2. Let omxplayer read this ( omxplayer /dev/shm/buffer.fifo )
3. Use an other command line window to put data into the fifo. Examples:
cat FILE.mp4 > /dev/shm/buffer.fifo
nc -p 5001 -l > /dev/shm/buffer.fifo


Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: planeta9999 en 28 de Febrero de 2018, 12:52:26
Así que puedes reescribir los manejadores para algunos de las señales (SIGUSR1, SIGUSR2) para que detenga la ejecución del video para que le de la oportunidad de leer algún valor que otro programa le envíe a través de una tubería para que cambie de video o que simplemente detenga la ejecución del mismo.

Por lo tanto puedes tener dos programas totalmente independientes, simplemente el programa que verifica el estado de las entradas le va a enviar las señales adecuadas al proceso del reproductor de vídeo, para que se detenga unos momentos a leer algo que le estas enviando, así te evitas el dichoso fork() y al no tener que cerrarse el reproductor de video podrías pensar en realizar transiciones más complejas(entre videos) de lo que podrías hacer con sólo cerrar y abrir de nuevo la aplicación.

------
Añado que aparentemente puedes enviar datos usando sigqueue. Nunca lo había visto pero podrías ser también prometedor

http://man7.org/linux/man-pages/man3/sigqueue.3.html


El problema es que parar el vídeo desde dentro del programa de propio reproductor no es tan sencillo. Yo solo lo he conseguido, esperando a que al menos se reproduzcan 2 segundos de vídeo, pero esto varía según el tamaño del vídeo.

La reproducción del vídeo se hace en un bucle que lee los datos del fichero a trozos y va alimentando a la GPU en un proceso bastante complejo, apenas documentado y difícil de entender. No he conseguido salir al instante del bucle sin que la GPU se bloquee.

Sin embargo, espero que el Pkill al proceso del reproductor de video, no dejé colgada la GPU, si no tendré que meter un pequeño retardo, pero no quedaría tan bien, porque los videos deben de responder al instante en función de señales externas.
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: tsk en 28 de Febrero de 2018, 14:00:43
Parar la reproducción, es un decir, pero lo puedes implementar de la forma que más te convenga, por ejemplo, que a la hora de recibir una interrupción cambie la fuente de los datos. No se como está hecho tu código, pero puedes probar lo que te menciono.

También veo arriba que mencionaste el omxplayer, así que o lo estas usando como base o estás usando la API de OpenMAX para tu programa, si esto es cierto, entonces OpenMAX te permite cambiar de estados y responde a eventos, muy parecido a lo que te comentaba de las señales, si los usas lo más seguro es que no se quede colgada la GPU, porque para responder a un evento o señal y/o comando, estos pasan antes por un cola de eventos, los cuales son atendidos al momento que el sistema los pueda atender.

Por ejemplo puedes mandarle el comando para poner el sistema en el estado de espera, el cambio no va a ser momentáneo, sino que va a entrar a una cola a esperar a ser atendido. Lo mismo sucede con los eventos.

Por lo pronto no cuento con una Raspberry Pi para probar, por lo que no puede hacer las pruebas.
Título: Re:Cancelar un proceso en Linux con Kill desde C++
Publicado por: planeta9999 en 01 de Marzo de 2018, 00:58:21
 
Si, el programa echa mano de Openmax, pero la documentación que hay al respecto es muy confusa. Lo único que encontré es el libro "Raspberry Pi GPU Audio Video Programming", que no me aclara mucho porque prácticamente es una colección de fuentes.

La idea original, era editar el programa en C++ de ejemplo, que reproduce un video, para meter una función que lee constantemente varios expansores de puertos MCP23s17, y en función del estado de varias matrices de señales, lanzar videos distintos.

Si un video está en ejecución, y se detecta una señal para lanzar otro video, hay que parar ese, y lanzar el nuevo. El problema es que para hacer eso, tocando el fuente del reproductor, hay que hacerlo dentro del bucle que alimenta constantemente la GPU con datos del video a reproducir. Eso lo conseguí, pero siempre hay que dejar que el video se reproduzca al menos un par de segundos o la GPU se queda colgada.

Al ver todo esto de lanzar un programa externo al principal y poder cancelarlo, me parece mejor idea. Por ahora no tengo necesidad de interactuar con el video, este solo se reproduce o se cancela cuando se tenga que lanzar uno nuevo.

Por ahora prefiero dejar el programa reproductor original sin tocar, y simplemente llamarlo desde un programa principal mío, para cancelarlo con pkill y lanzar uno nuevo cuando sea necesario reproducir otro video.

Si que estuve mirando algo para mezclar texto con ese vídeo en tiempo de ejecución, es lo único que me interesaría para interactuar con el vídeo en curso. Las pruebas que hice funcionaron bastante bien con varios efectos de texto sobre el vídeo, pero es todo muy complejo y la documentación que hay se hace pesada de manejar.

También me gustaría reproducir uno o varios videos simultaneamente en ventanas, ahora sale a pantalla completa. Algo se cuenta en el libro al respecto, aún lo tengo que probar.

La posibilidad de lanzar el reproductor una sola vez desde un programa principal mío, e interactuar con este por medio de algún sistema de comunicación, todo esto de las "pipes", también se ve interesante. En el ejemplo que he puesto antes creando una especie de cola FIFO, creo que lo hacen así.


(https://i.ebayimg.com/images/g/RMoAAOSwImRYct2u/s-l300.jpg)