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:
- Crear la lista de elementos (no es necesario que sea shared
- Crear una variable de condición o semáforo(leer perldoc threads)
- La cantidad de elementos de la lista, dividirla entre N Threads
- Cada thread (función asíncrona) tomará las partes en las que se dividió la lista (posición inicial, posición final)
- 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ó
- 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,