• Publicidad

threads y condición

¿Ya sabes lo que es una referencia? Has progresado, el nível básico es cosa del pasado y ahora estás listo para el siguiente nivel.

threads y condición

Notapor p0fk » 2009-09-21 22:55 @996

Hola a todos. Tengo nuevamente problema de threads.
Primero les dejo una prueba de concepto para tratar de entender mejor.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use threads;
  3. system'clear';
  4. my@SALIDA : shared=(12,12,12,12,12,12,12,12,12,12,15);
  5.  
  6. $THREAD_NUM_COLUMN = 5;
  7.  
  8. for(0 .. $THREAD_NUM_COLUMN-1) {
  9.     push @threads, threads->create(\&CHECKING);
  10. }
  11. sleep(1);
  12. foreach $THREAD_FOR (@threads){
  13.     #print"finalizado ".$THREAD_FOR->tid() , "\n";              ##DEBUG
  14.     $OUT_NUMBER=   $THREAD_FOR->join();
  15. }
  16.  
  17. print"RETORNADO: $OUT_NUMBER\n";
  18.  
  19. sub CHECKING{
  20.     my@NUMBER_ARRAY : shared=(0..100);
  21.  
  22.     $TID_COLUMN = threads->tid();
  23.     $I = $TID_COLUMN - 1;
  24.     while ( $I < @NUMBER_ARRAY ) {
  25.         $INT_COLMN = $NUMBER_ARRAY[$I];
  26.         $COMPARA   = $SALIDA[$I];
  27.         print"NUMERO: $INT_COLMN => HILO N°: $I => COMPARA: $COMPARA\n";  ##DEBUG
  28.         sleep(2);
  29.         $I += $THREAD_NUM_COLUMN;
  30.         last if($COMPARA != 12);
  31.         #print"SALIDA: $INT_COLMN\n";
  32.     }
  33.  
  34.     return$INT_COLMN;
  35. }
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4


Ok, el objetivo de este código es contar en qué posición se encuentra un objeto.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
my@SALIDA : shared=(12,12,12,12,12,12,12,12,12,12,15);
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Este array es el que chequea, en dónde quiero que, cuando sea distinto a 12, los hilos dejen de trabajar y retorne la posición en la que se encuentra.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
last if($COMPARA != 12);
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


El problema es que retorna otro valor :S , que no es el de la condición

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
last if($COMPARA != 12); ...
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Esta es la salida:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
NUMERO: 0 => HILO N°: 0 => COMPARA: 12
NUMERO: 1 => HILO N°: 1 => COMPARA: 12
NUMERO: 2 => HILO N°: 2 => COMPARA: 12
NUMERO: 3 => HILO N°: 3 => COMPARA: 12
NUMERO: 4 => HILO N°: 4 => COMPARA: 12
NUMERO: 5 => HILO N°: 5 => COMPARA: 12
NUMERO: 6 => HILO N°: 6 => COMPARA: 12
NUMERO: 7 => HILO N°: 7 => COMPARA: 12
NUMERO: 8 => HILO N°: 8 => COMPARA: 12
NUMERO: 9 => HILO N°: 9 => COMPARA: 12
NUMERO: 10 => HILO N°: 10 => COMPARA: 15
NUMERO: 11 => HILO N°: 11 => COMPARA:
NUMERO: 12 => HILO N°: 12 => COMPARA:
NUMERO: 13 => HILO N°: 13 => COMPARA:
NUMERO: 14 => HILO N°: 14 => COMPARA:
RETORNADO: 14
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Quiero que me devuelva en este caso 10...

Ojalá se entienda lo que trato de decir (no soy bueno explicando) ¡Saludos!...
Última edición por explorer el 2009-09-22 09:32 @439, editado 2 veces en total
Razón: Ortografía, indentación del código
p0fk
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2009-06-11 22:17 @970

Publicidad

Re: threads condicion

Notapor Perl user » 2009-09-22 01:30 @104

Qué tal,

Entiendo el problema que intentas resolver, bueno, más o menos. Sin embargo, incluso tu solución es un poco rara en cuestión a lo que nos quieres mostrar o del problema que intentas resolver. Te comento al respecto en cuanto a tu solución y luego te explicaré por qué obtienes los resultados no deseados.

En primera instancia, y la parte que mete más ruido (y por lo tanto aún mas difícil de entender) es la variable @NUMBER_ARRAY. Por lo que veo, intenta ser un tipo de lista que almacena los índices posibles a buscar en tu verdadera lista de números compartidos para cada thread. No se necesita absolutamente para nada dicha variable, si lo que quieres saber es en qué posición está dicho elemento. El segundo problema... hacerla shared. Por concepto básico en cuanto a recursos compartidos entre threads, recuerda que todos los datos declarados de manera local o mejor dicho, dentro de la función que será invocada por algún thread de manera asíncrona permanecen locales a dicho contexto. El que lo declares como shared no le beneficia (y en teoría ni le perjudica) en nada. Tercer problema... utilizar a sleep() como medio de pseudo-sincronización entre threads. Recuerda que hablamos de ejecución asíncrona, y dichos contextos en ejecución son controlados por un scheduler que muy posiblemente cambie en cada plataforma.

Ahora, en cuanto a los resultados erróneos. Los threads, como mencioné arriba, no son ni síncronos ni secuenciales, independientemente del tiempo en el que los estás poniendo a dormir, el scheduler otorgará o cederá tiempo en el CPU de acuerdo a cómo él crea conveniente, por lo tanto, un mismo thread puede incluso tomar ejecución en el CPU dos veces seguidas. Habiendo dicho esto... en la línea 29 tienes una instrucción que dice $I += $THREAD_NUM_COLUMN, que toma el id del thread y lo suma así mismo. Imagina que el thread 4 (t4) estaba en ejecución, y que el scheduler quiere darle tiempo de ejecución a él nuevamente... t4 tendrá un valor de 8... y 8 no cumple con tu condición de finalización. Si el scheduler decide de nuevo darle tiempo de CPU a dicho thread, el valor será de 12, por lo que ahora ya ni siquiera está dentro de los límites de tu array compartido y así seguirá.

Por otro lado... en tu código esperas a que cada thread termine invocando join(), para lo cual cada uno retornará algún valor que le corresponda a si se cumplió o no la condición. Pero, en realidad lo sobreescribes con algún valor posible, que incluye a todos aquellos valores que se salieron del rango de tu array compartido.

La recomendación es que... elimines ese array de posiciones (0.100) y utilices el mismo array que declaraste como compartido para ver las posiciones, y... en cuanto a cómo divides los threads, te recomiendo que mejor le des un rango a buscar a cada uno de los 5 threads; si tienes 10 elementos, dale 2 elementos a cada uno... y utilizar una variable de condición cada vez que cheque un elemento donde, antes de checar el siguiente elemento de su lista de elementos otorgados, mejor verifique esa variable de condición a ver si otro thread no ha encontrado el elemento en la lista. Es un algoritmo de divide y vencerás trivial(devide and conquer), a menos que como te indiqué al inicio del mensaje, que con el ejemplo que nos quisiste dar en realidad tu problema sea otro diferente.

El algoritmo es algo como lo siguiente:

  1. Crear la lista de elementos (no es necesario que sea shared
  2. Crear una variable de condición o semáforo(leer perldoc threads)
  3. La cantidad de elementos de la lista, dividirla entre N Threads
  4. Cada thread (función asíncrona) tomará las partes en las que se dividió la lista (posición inicial, posición final)
  5. Dentro de la función, esas posiciones revisarlas de manera asíncrona, verificando si algún thread no ha establecido el semáforo o variable de condición a un valor verdadero indicando que el elemento a buscar ya se encontró
  6. Retornar el valor de la posición en la que se encontró el elemento.

Si te fijas, dicho algoritmo no necesita de una estructura completamente compartida (como la lista de tus elementos), de lo contrario, delega la responsabilidad de detenerse o continuar revisando cantidades discretas de elementos a una estructura mas pequeña y con menos carga como lo es un semáforo o una variable de condición.

Un saludo y suerte con el problema,
Marco A. Manzo
[email protected]
http://www.unixmonkeys.com/amnesiac/
Perl Programming Language
Perl user
Maestro honorario
Maestro honorario
 
Mensajes: 271
Registrado: 2004-11-03 21:11 @924

Re: threads y condición

Notapor explorer » 2009-09-22 19:08 @839

Si no lo he entendido mal, parece que p0fk está intentando repartir el trabajo de búsqueda entre todos los hilos. Es decir, el primer hilo buscará en los índices 0, 5, 10, 15, etc. El segundo irá mirando el 6, 11, 16, etc. Así hasta el final del arreglo de búsqueda o que lo encuentre.

Aquí pongo una forma de hacerlo, olvidándonos del arreglo @NUMBER_ARRAY, que solo servía como alimentador de índices de búsqueda.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5.  
  6. use threads;
  7.  
  8. system 'clear';
  9.  
  10. $|++; # no caché
  11.  
  12. ## Vector de búsqueda
  13. my @salida = ((12) x 10, 15);
  14.  
  15. ## Número de hilos
  16. my $THREAD_NUM_COLUMN = 5;
  17.  
  18. ## Creación de los hilos
  19. my @hilos;
  20.  
  21. for (0 .. $THREAD_NUM_COLUMN-1) {
  22.     push @hilos, threads->create(\&comprobando);
  23. }
  24.  
  25. ## Esperarles para terminar
  26. for my $hilo (@hilos) {
  27.     my $salida = $hilo->join();
  28. }
  29.  
  30. ## Función de búsqueda
  31. sub comprobando {
  32.  
  33.     my $hilo = threads->tid();
  34.  
  35.     my $i = $hilo - 1;
  36.  
  37.     while ($i < @salida) {
  38.  
  39.         print "Hilo $hilo buscando en posición $i\n";
  40.  
  41.         if ($salida[$i] != 12) {
  42.             print "Hilo $hilo encontró el diferente en posición $i\n";
  43.             return;
  44.         }
  45.     }
  46.     continue {
  47.         $i += $THREAD_NUM_COLUMN;
  48.         sleep 1 + rand 4;
  49.     }
  50. }
  51.  
  52. __END__
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

La salida es (una de las posibles):
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Hilo 1 buscando en posición 0
Hilo 2 buscando en posición 1
Hilo 3 buscando en posición 2
Hilo 4 buscando en posición 3
Hilo 5 buscando en posición 4
Hilo 1 buscando en posición 5
Hilo 2 buscando en posición 6
Hilo 3 buscando en posición 7
Hilo 1 buscando en posición 10
Hilo 1 encontró el diferente en posición 10
Hilo 4 buscando en posición 8
Hilo 5 buscando en posición 9
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Esta otra versión es más entretenida: usamos el rand() para colocar al valor maldito en una posición desconocida. Así, no sabemos qué hilo lo encontrará. Además, hay un semáforo para indicar a todos que ya se encontró.

Observar, también, que aquí sí que usamos el módulo threads::shared para crear variables compartidas entre los hilos.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5.  
  6. use threads;
  7. use threads::shared;
  8.  
  9. system 'clear';
  10.  
  11. $|++; # no caché
  12.  
  13. ## Vector de búsqueda
  14. my @salida = (12) x 300;
  15. $salida[rand @salida] = 15;    # Elegimos uno al azar
  16.  
  17. ## Número de hilos
  18. my $THREAD_NUM_COLUMN = 5;
  19.  
  20. ## Bandera de encontrado
  21. my $encontrado : shared;
  22.  
  23. ## Creación de los hilos
  24. $encontrado = 0;
  25. my @hilos;
  26. for (0 .. $THREAD_NUM_COLUMN-1) {
  27.     push @hilos, threads->create(\&comprobando);
  28. }
  29.  
  30. ## Esperarles para terminar
  31. for my $hilo (@hilos) {
  32.     my $salida = $hilo->join();
  33. }
  34.  
  35. ## Función de búsqueda
  36. sub comprobando {
  37.  
  38.     my $hilo = threads->tid();
  39.  
  40.     my $i = $hilo - 1;
  41.  
  42.     while (!$encontrado and $i < @salida) {
  43.  
  44.         print "Hilo $hilo buscando en posición $i\n";
  45.  
  46.         if ($salida[$i] != 12) {
  47.             print "Hilo $hilo encontró el diferente en posición $i\n";
  48.             $encontrado = 'sí';
  49.         }
  50.     }
  51.     continue {
  52.         $i += $THREAD_NUM_COLUMN;
  53.         sleep 1 + rand 2;
  54.     }
  55. }
  56.  
  57. __END__
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Intermedio

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 10 invitados