no me aclaro con las id y asesinatos de procesos...

Started by Futu-block, December 08, 2010, 06:52:08 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

SplinterGU

tambien puedes compilar con -g y ejecutar con -d para ver el orden de ejecucion del codigo.
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

SplinterGU

ejemplo 1 (con -g y -d)

Quote
Loading... mod_say.so
Loading... mod_proc.so
Loading... libsdlhandler.so
Loading... libkey.so
Loading... mod_key.so


>>> Instance:MAIN ProcID:65536 StackUsed:0/4096
onexit.prg:33         pa = a();

>>> Instance:A ProcID:65537 StackUsed:0/4096
onexit.prg:7          while(1)
onexit.prg:8          say("A frame...");
A frame...
onexit.prg:9          frame;
onexit.prg:34         pb = b();

>>> Instance:B ProcID:65538 StackUsed:0/4096
onexit.prg:19         while(1)
onexit.prg:20         say("B frame...");
B frame...
onexit.prg:21         frame;
onexit.prg:36         for ( i = 0; i < 4; i++)
onexit.prg:36         for ( i = 0; i < 4; i++)
onexit.prg:37         if ( i == 2 )
onexit.prg:41         say("main frame...");
main frame...
onexit.prg:42         frame;

>>> Instance:MAIN ProcID:65536 StackUsed:0/4096
onexit.prg:43         say("main continua...");
main continua...
onexit.prg:44         end
onexit.prg:36         for ( i = 0; i < 4; i++)
onexit.prg:36         for ( i = 0; i < 4; i++)
onexit.prg:37         if ( i == 2 )
onexit.prg:41         say("main frame...");
main frame...
onexit.prg:42         frame;

>>> Instance:B ProcID:65538 StackUsed:0/4096
onexit.prg:22         say("B continua...");
B continua...
onexit.prg:23         end
onexit.prg:19         while(1)
onexit.prg:20         say("B frame...");
B frame...
onexit.prg:21         frame;

>>> Instance:A ProcID:65537 StackUsed:0/4096
onexit.prg:10         say("A continua...");
A continua...
onexit.prg:11         end
onexit.prg:7          while(1)
onexit.prg:8          say("A frame...");
A frame...
onexit.prg:9          frame;

>>> Instance:MAIN ProcID:65536 StackUsed:0/4096
onexit.prg:43         say("main continua...");
main continua...
onexit.prg:44         end
onexit.prg:36         for ( i = 0; i < 4; i++)
onexit.prg:36         for ( i = 0; i < 4; i++)
onexit.prg:37         if ( i == 2 )
onexit.prg:38         say("main kill B...");
main kill B...
onexit.prg:39         signal(pb,s_kill);
onexit.prg:41         say("main frame...");
main frame...
onexit.prg:42         frame;

>>> Instance:B ProcID:65538 StackUsed:0/4096

>>> Instance:B ProcID:65538 StackUsed:0/4096
onexit.prg:25         say("B muerto!");
B muerto!

>>> Instance:A ProcID:65537 StackUsed:0/4096
onexit.prg:10         say("A continua...");
A continua...
onexit.prg:11         end
onexit.prg:7          while(1)
onexit.prg:8          say("A frame...");
A frame...
onexit.prg:9          frame;

>>> Instance:MAIN ProcID:65536 StackUsed:0/4096
onexit.prg:43         say("main continua...");
main continua...
onexit.prg:44         end
onexit.prg:36         for ( i = 0; i < 4; i++)
onexit.prg:36         for ( i = 0; i < 4; i++)
onexit.prg:37         if ( i == 2 )
onexit.prg:41         say("main frame...");
main frame...
onexit.prg:42         frame;

>>> Instance:A ProcID:65537 StackUsed:0/4096
onexit.prg:10         say("A continua...");
A continua...
onexit.prg:11         end
onexit.prg:7          while(1)
onexit.prg:8          say("A frame...");
A frame...
onexit.prg:9          frame;

>>> Instance:MAIN ProcID:65536 StackUsed:0/4096
onexit.prg:43         say("main continua...");
main continua...
onexit.prg:44         end
onexit.prg:36         for ( i = 0; i < 4; i++)
onexit.prg:36         for ( i = 0; i < 4; i++)
onexit.prg:46         let_me_alone();

>>> Instance:A ProcID:65537 StackUsed:0/4096

>>> Instance:A ProcID:65537 StackUsed:0/4096
onexit.prg:13         say("A muerto!");
A muerto!

ejemplo 2 (con -g y -d)

Quote
Loading... mod_say.so
Loading... mod_proc.so
Loading... libsdlhandler.so
Loading... libkey.so
Loading... mod_key.so


>>> Instance:MAIN ProcID:65536 StackUsed:0/4096
onexit.prg:40         pa = a();

>>> Instance:A ProcID:65537 StackUsed:0/4096
onexit.prg:9          while(1)
onexit.prg:10         i++;
onexit.prg:11         if ( i == 2 )
onexit.prg:15         say("A frame...");
A frame...
onexit.prg:16         frame;
onexit.prg:41         pb = b();

>>> Instance:B ProcID:65538 StackUsed:0/4096
onexit.prg:26         while(1)
onexit.prg:27         say("B frame...");
B frame...
onexit.prg:28         frame;
onexit.prg:43         for ( i = 0; i < 4; i++)
onexit.prg:43         for ( i = 0; i < 4; i++)
onexit.prg:44         say("main frame...");
main frame...
onexit.prg:45         frame;

>>> Instance:MAIN ProcID:65536 StackUsed:0/4096
onexit.prg:46         say("main continua...");
main continua...
onexit.prg:47         end
onexit.prg:43         for ( i = 0; i < 4; i++)
onexit.prg:43         for ( i = 0; i < 4; i++)
onexit.prg:44         say("main frame...");
main frame...
onexit.prg:45         frame;

>>> Instance:B ProcID:65538 StackUsed:0/4096
onexit.prg:29         say("B continua...");
B continua...
onexit.prg:30         end
onexit.prg:26         while(1)
onexit.prg:27         say("B frame...");
B frame...
onexit.prg:28         frame;

>>> Instance:A ProcID:65537 StackUsed:0/4096
onexit.prg:17         say("A continua...");
A continua...
onexit.prg:18         end
onexit.prg:9          while(1)
onexit.prg:10         i++;
onexit.prg:11         if ( i == 2 )
onexit.prg:12         say("A auto kill...");
A auto kill...
onexit.prg:13         signal(id,s_kill);

>>> Instance:A ProcID:65537 StackUsed:0/4096
onexit.prg:20         say("A muerto!");
A muerto!

>>> Instance:MAIN ProcID:65536 StackUsed:0/4096
onexit.prg:46         say("main continua...");
main continua...
onexit.prg:47         end
onexit.prg:43         for ( i = 0; i < 4; i++)
onexit.prg:43         for ( i = 0; i < 4; i++)
onexit.prg:44         say("main frame...");
main frame...
onexit.prg:45         frame;

>>> Instance:B ProcID:65538 StackUsed:0/4096
onexit.prg:29         say("B continua...");
B continua...
onexit.prg:30         end
onexit.prg:26         while(1)
onexit.prg:27         say("B frame...");
B frame...
onexit.prg:28         frame;

>>> Instance:MAIN ProcID:65536 StackUsed:0/4096
onexit.prg:46         say("main continua...");
main continua...
onexit.prg:47         end
onexit.prg:43         for ( i = 0; i < 4; i++)
onexit.prg:43         for ( i = 0; i < 4; i++)
onexit.prg:44         say("main frame...");
main frame...
onexit.prg:45         frame;

>>> Instance:B ProcID:65538 StackUsed:0/4096
onexit.prg:29         say("B continua...");
B continua...
onexit.prg:30         end
onexit.prg:26         while(1)
onexit.prg:27         say("B frame...");
B frame...
onexit.prg:28         frame;

>>> Instance:MAIN ProcID:65536 StackUsed:0/4096
onexit.prg:46         say("main continua...");
main continua...
onexit.prg:47         end
onexit.prg:43         for ( i = 0; i < 4; i++)
onexit.prg:43         for ( i = 0; i < 4; i++)
onexit.prg:49         let_me_alone();

>>> Instance:B ProcID:65538 StackUsed:0/4096

>>> Instance:B ProcID:65538 StackUsed:0/4096
onexit.prg:32         say("B muerto!");
B muerto!
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

SplinterGU

Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Arcontus

#18
Ya veo lo que comentas SplinterGU, pero no es esa la pregunta y creo que es importante. A ver como lo explico.

Lo mas facil es verlo en el código que puse:

PROCESS b(int *salir)
BEGIN
    while((*salir) == 0)
        FRAME;
    END
END


El proceso B seguira funcionando mientras su puntero salir valga 0. Salir pertenece al proceso A. Si B consulta el valor de salir de A cuando A no exista, el programa petará.

PROCESS a()
PRIVATE
    int salir;
END
BEGIN
    salir = 0;
    b(&salir);
    LOOP
        FRAME;
    END
OnExit:
    salir = 1;
END


El proceso A, al recibir un signal S_KILL cambia el valor de salir a 1 para que el proceso B termine, pero realmente A llega antes a su END antes de que el proceso B pueda consultar la variable "salir".

...
signal_skill(id_a, s_kill);
...

Espero haberlo explicado con claridad el ejemplo. 

El caso es que con todas las pruebas que he hecho, y son muchisimas, no he detectado que este sistema provoque inestabilidad o pete del programa, por lo que sin ver que sucede exactamente (a nivel interno de bennu me refiero), me atrevo a afirmar que el proceso "muerto", en realidad es mas bien un "zombie" donde sus variables de tipo PUNTERO siguen siendo perfectamente accesibles hasta que el resto de procesos alcancen el siguiente FRAME.  Algo así como que para morir el proceso deba recorrer ciertas listas internas de bennu y ello conlleve esta accesibilidad temporal vinculada de alguna manera al FRAME. Pero claro, no puedo estar 100% seguro de que esto sea así.

Ojo, hablo de PUNTEROS es decir apuntadores de memoria, no de acceder a la estructura del proceso del tipo "father.salir" (para el caso de que salir fuera pública en vez de privada). Esto segundo seguro que no funciona, por que "father" ya está marcado para morir y bennu no dejaría recorrer su arbol de datos.

¿Me explico? ¿Es correcto?

En el caso que pone Splinter, lo que estamos observando es el cierre del proceso y como es lógico salen los SAY en el orden de ejecución, pero obviamente después de que un proceso alcanza ese END de final de proceso, la cosa no acaba ahi, sino que pasan cosas en las tablas de control de bennu y sus oscuros misterios misteriosos.

El quid es contestar si el código anterior es totalmente valido o si su uso genera inestabilidad (la cual repito no he visto).

Gracias por la paciencia, estoy muy interesado en desvelar este misterio. :)
5Leaps, el primer juego comercial desarrollado para BennuGD. http://www.5leaps.com

SplinterGU

no es valido... es solo suerte, es solo porque el area de memoria aun no ha sido reutilizada por nadie, pero es un area de datos que ya no pertenece a nadie, y esta liberada...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

SplinterGU

para demostrar lo que digo... agregue log a las funciones instance_new e instance_destroy (que son donde se alocan y liberan los bloques de memoria de las variables de los procesos):

Quote
instance_new
instance_new
A frame...
instance_new
B frame...
main frame...
main continua...
main frame...
B continua...
B frame...
A continua...
A frame...
main continua...
main kill B...
main frame...
B muerto!
B bye bye!
instance_destroy
A continua...
A frame...
main continua...
main frame...
A continua...
A frame...
main continua...
instance_destroy
A muerto!
A bye bye!
instance_destroy

como ves, el destroy use ejecuta antes que el 2do proceso se ejecute...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

SplinterGU

pero... podes hacer un truco para que esto sea seguro...

el truco esta en usar diferentes priority (mayor en el proceso con OnExit y menor en el que chequea el puntero) y frame en el OnExit...

la cosa seria algo asi...


PROCESS b(int *salir)
BEGIN
    priority = father.priority - 1;
    while((*salir) == 0)
        FRAME;
    END
END

PROCESS a()
PRIVATE
    int salir;
END
BEGIN
    salir = 0;
    b(&salir);
    LOOP
        FRAME;
    END
OnExit:
    salir = 1;
    frame;
END


el punto esta en que b() deberia tener una prioridad inferior que a(), y usar el frame, ahi si podrias hacer de forma segura lo que queres.

como detalle adicional, internamente, el motor tiene un loop que recorre todos los procesos y los ejecuta (solo ejecuta los que esten vivos y no hayan completado su frame o los que tengan estado killed o dead), cuando termina el loop, actualiza los contadores de porcentaje de frame completado y vuelve a hacer el loop... en este punto, segun lo que mencione antes, podemos darnos cuenta que los procesos vivos con su frame completo no se volveran a ejecutar, pero los que estan en dead o killed se volveran a ejecutar hasta que desparezcan... una vez que el loop detecta que no ejecuto ningun proceso, ahi es donde se completa realmente el FRAME de todos los procesos y reinicia el ciclo... por eso, un proceso killeado, por mas frame que tenga, se resuelve en el frame que murio... cuando el FRAME es completado el proceso no existe mas...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

SplinterGU

#22
tambien podes simplemente hacer esto...


PROCESS b()
BEGIN
    LOOP
        FRAME;
    END
END

PROCESS a()
PRIVATE
    int pb;
END
BEGIN
    pb = b();
    LOOP
        FRAME;
    END
OnExit:
    signal(pb,s_kill);
END


o


    signal(id_a, s_kill_tree);


que mata a A y a su descendencia.
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Arcontus

#23
Gracias SplinterGU, muy aclaratorio.

Respecto a lo que comentas del priority, no veo en que caso puede "mejorar" ya que en mi ejemplo, hasta que no alcanza onExit: no realiza el cambio en la variable "salir", por lo que la prioridad con la que se ejecuten los procesos daría lo mismo.

Respecto a s_kill_tree, tengo una duda: si un proceso tiene más de un hijo, y este a su vez tiene más de un nieto, tengo entendido que este sistema solo recorre una única linea, en concreto la última linea de creación de hijos ¿no es cierto? De todas formas, no es exactamente lo que necesito.

Pues vaya problemón... ¿No se podría (digo yo) hacer que FRAME; dentro de OnExit: se comportara igual que siempre, y asi se pueden sincronizar procesos en su defuncion?
Actualmente FRAME dentro de OnExit: es FRAME(0), lo cual no entiendo muy bien el motivo e impide por ejemplo abordar este "problema" con esta solución. Tampoco es el fin del mundo, ya que se puede hacer de una manera algo más tediosa, pero seria genialisimo poder sincronizar cosas antes de que los procesos murieran.

Gracias,
Un saludo!
5Leaps, el primer juego comercial desarrollado para BennuGD. http://www.5leaps.com

SplinterGU

la prioridad si te servira, porque hara que el OnExit del proceso A se ejecute antes que el proceso B... con lo que te aseguras que "salir" exista y no estes apuntando a un area de memoria fantasma o ocupada por otro nuevo proceso...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

SplinterGU

por otro lado, ya me adelante a lo que me preguntaste y ya estoy probando un cambio para hacer que FRAME dentro de OnExit, se comporte igual que en otras partes del codigo.

pero de paso estoy arreglando otras cosas que tienen que ver con esa parte de la logica y se relacionan con el debugger.
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Arcontus

Quote from: SplinterGU on February 14, 2018, 04:26:10 PM
por otro lado, ya me adelante a lo que me preguntaste y ya estoy probando un cambio para hacer que FRAME dentro de OnExit, se comporte igual que en otras partes del codigo.

pero de paso estoy arreglando otras cosas que tienen que ver con esa parte de la logica y se relacionan con el debugger.

Que gran noticia!! La verdad es que este cambio simplificaría el uso de OnExit.

Un saludo!
5Leaps, el primer juego comercial desarrollado para BennuGD. http://www.5leaps.com

Drumpi

Yo te recomendaría que no te complicases tanto. Eso de un puntero para salir es muy "C".

Si quieres salir de una parte del código, he comprobado que las dos mejores soluciones son las siguientes:
- Tener un proceso de control que sea el encargado de decidir quié vive y quién muere, y en qué orden.
- Que "salir" y todas las variables que sean conflictivas en el orden de ejecución, sean variables globales, y que cada proceso reaccione cuando pueda (es interesante porque de esta forma, el proceso que ponga la variable "salir" a "true" tiene un valor de priority, y cada proceso independiente el suyo propio, que se ejecutará en el mismo frame si son más lentos, o en el siguiente si son más rápidos).

En cualquier caso, intenta evitar en todo lo posible punteros a variables internas de procesos. Puedes usar las locals o las public sin pegas porque tienes EXISTS para comprobar que el proceso aun existe. En cualquier otro caso, recomendaría que las varibles fuesen globales.
Por ejemplo, si necesitas crear 4 procesos con datos de altura, peso y edad, no uses variables privadas, usa un array dinámico (o lista enlazada) con un tipo que te hayas creado tu, y que tenga otra variable con el ID del proceso que lo ha creado. De esta forma, cualquier proceso puede buscar si existe el nodo del proceso xxx, y el propio proceso xxx podría tener un puntero privado directo al nodo.
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

Arcontus

Quote from: Drumpi on May 07, 2018, 01:04:20 AM
Yo te recomendaría que no te complicases tanto. Eso de un puntero para salir es muy "C".

Si quieres salir de una parte del código, he comprobado que las dos mejores soluciones son las siguientes:
- Tener un proceso de control que sea el encargado de decidir quié vive y quién muere, y en qué orden.
- Que "salir" y todas las variables que sean conflictivas en el orden de ejecución, sean variables globales, y que cada proceso reaccione cuando pueda (es interesante porque de esta forma, el proceso que ponga la variable "salir" a "true" tiene un valor de priority, y cada proceso independiente el suyo propio, que se ejecutará en el mismo frame si son más lentos, o en el siguiente si son más rápidos).

En cualquier caso, intenta evitar en todo lo posible punteros a variables internas de procesos. Puedes usar las locals o las public sin pegas porque tienes EXISTS para comprobar que el proceso aun existe. En cualquier otro caso, recomendaría que las varibles fuesen globales.
Por ejemplo, si necesitas crear 4 procesos con datos de altura, peso y edad, no uses variables privadas, usa un array dinámico (o lista enlazada) con un tipo que te hayas creado tu, y que tenga otra variable con el ID del proceso que lo ha creado. De esta forma, cualquier proceso puede buscar si existe el nodo del proceso xxx, y el propio proceso xxx podría tener un puntero privado directo al nodo.
Después de 5 años peleandome con Bennu, te doy la razón en que este modo es muy "C" y de que no es la mejor manera tal y como está estructurado el tema del FRAME en el OnExit, pero a veces es lo que más conviene. Y no me voy a pegar el rollo poniendo ejemplos ya que también utilizo tus soluciones para unos casos, pero para otros lo tengo que hacer de esta manera.
También estarás de acuerdo conmigo de que si FRAME en OnExit funcionara como en el resto del código, a: sería más claro para todo desarrollador que empiece (yo me enteré hace relativamente poco y por que me petaba una cosa del proyecto) y b: ya daría igual como decidas controlar los procesos. Tendrias libertad para hacer lo que más te conveniera.
En resumen: Hoy por hoy si no quieres tener problemas, haced lo que dice Drumpi, pero sería mejor no tener esa "limitación".



5Leaps, el primer juego comercial desarrollado para BennuGD. http://www.5leaps.com

SplinterGU

Quote from: Arcontus on May 08, 2018, 04:26:39 PM
Quote from: Drumpi on May 07, 2018, 01:04:20 AM
Yo te recomendaría que no te complicases tanto. Eso de un puntero para salir es muy "C".

Si quieres salir de una parte del código, he comprobado que las dos mejores soluciones son las siguientes:
- Tener un proceso de control que sea el encargado de decidir quié vive y quién muere, y en qué orden.
- Que "salir" y todas las variables que sean conflictivas en el orden de ejecución, sean variables globales, y que cada proceso reaccione cuando pueda (es interesante porque de esta forma, el proceso que ponga la variable "salir" a "true" tiene un valor de priority, y cada proceso independiente el suyo propio, que se ejecutará en el mismo frame si son más lentos, o en el siguiente si son más rápidos).

En cualquier caso, intenta evitar en todo lo posible punteros a variables internas de procesos. Puedes usar las locals o las public sin pegas porque tienes EXISTS para comprobar que el proceso aun existe. En cualquier otro caso, recomendaría que las varibles fuesen globales.
Por ejemplo, si necesitas crear 4 procesos con datos de altura, peso y edad, no uses variables privadas, usa un array dinámico (o lista enlazada) con un tipo que te hayas creado tu, y que tenga otra variable con el ID del proceso que lo ha creado. De esta forma, cualquier proceso puede buscar si existe el nodo del proceso xxx, y el propio proceso xxx podría tener un puntero privado directo al nodo.
Después de 5 años peleandome con Bennu, te doy la razón en que este modo es muy "C" y de que no es la mejor manera tal y como está estructurado el tema del FRAME en el OnExit, pero a veces es lo que más conviene. Y no me voy a pegar el rollo poniendo ejemplos ya que también utilizo tus soluciones para unos casos, pero para otros lo tengo que hacer de esta manera.
También estarás de acuerdo conmigo de que si FRAME en OnExit funcionara como en el resto del código, a: sería más claro para todo desarrollador que empiece (yo me enteré hace relativamente poco y por que me petaba una cosa del proyecto) y b: ya daría igual como decidas controlar los procesos. Tendrias libertad para hacer lo que más te conveniera.
En resumen: Hoy por hoy si no quieres tener problemas, haced lo que dice Drumpi, pero sería mejor no tener esa "limitación".





creo que ese cambio ya lo libre... sino, esta en el horno... viene a fuego lento... asi que habra que esperar... estoy cambiando cosas del core relacionadas con el debugger... bah, hay cambios en el debugger, callbacks del core, y otras cosas...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2