2011-03-30 9 views
7

Estoy utilizando el jsr166y ForkJoinPool para distribuir tareas de cómputo entre subprocesos. Pero claramente debo estar haciendo algo mal.paralelismo de ForkJoinPool = 1 interbloqueo

Mis tareas parecen funcionar sin problemas si creo el ForkJoinPool con paralelismo> 1 (el valor predeterminado es Runtime.availableProcessors(); he estado trabajando con 2-8 hilos). Pero si creo el ForkJoinPool con paralelismo = 1, veo deadlocks después de un número impredecible de iteraciones.

Sí - establecer el paralelismo = 1 es una práctica extraña. En este caso, estoy perfilando un algoritmo paralelo a medida que aumenta el conteo de subprocesos, y quiero comparar la versión paralela, ejecutar con un solo subproceso, con una implementación serial de línea de base, para determinar con precisión la sobrecarga de la implementación paralela .

A continuación se muestra un ejemplo simple que ilustra el problema que estoy viendo. La 'tarea' es una iteración ficticia sobre una matriz fija, dividida recursivamente en 16 subtareas.

Si se ejecuta con THREADS = 2 (o más), se ejecuta confiablemente hasta su finalización, pero si se ejecuta con THREADS = 1, invariablemente se bloquea. Después de un número impredecible de iteraciones, el ciclo principal se cuelga en ForkJoinPool.invoke(), esperando en task.join(), y sale el hilo de trabajo.

estoy corriendo con JDK 1.6.0_21 y 1.6.0_22 bajo Linux, y el uso de una versión de jsr166y descargado hace unos días desde el sitio web de Doug Lea (http://gee.cs.oswego.edu/dl/concurrency-interest/index.html)

¿Alguna sugerencia para lo que me falta ? Muchas gracias de antemano.

package concurrent; 

import jsr166y.ForkJoinPool; 
import jsr166y.RecursiveAction; 

public class TestFjDeadlock { 

    private final static int[] intArray = new int[256 * 1024]; 
    private final static float[] floatArray = new float[256 * 1024]; 

    private final static int THREADS = 1; 
    private final static int TASKS = 16; 
    private final static int ITERATIONS = 10000; 

    public static void main(String[] args) { 

     // Initialize the array 
     for (int i = 0; i < intArray.length; i++) { 
      intArray[i] = i; 
     } 

     ForkJoinPool pool = new ForkJoinPool(THREADS); 

     // Run through ITERATIONS loops, subdividing the iteration into TASKS F-J subtasks 
     for (int i = 0; i < ITERATIONS; i++) { 
      pool.invoke(new RecursiveIterate(0, intArray.length)); 
     } 

     pool.shutdown(); 
    } 

    private static class RecursiveIterate extends RecursiveAction { 

     final int start; 
     final int end; 

     public RecursiveIterate(final int start, final int end) { 
      this.start = start; 
      this.end = end; 
     } 

     @Override 
     protected void compute() { 

      if ((end - start) <= (intArray.length/TASKS)) { 
       // We've reached the subdivision limit - iterate over the arrays 
       for (int i = start; i < end; i += 3) { 
        floatArray[i] += i + intArray[i]; 
       } 

      } else { 
       // Subdivide and start new tasks 
       final int mid = (start + end) >>> 1; 
       invokeAll(new RecursiveIterate(start, mid), new RecursiveIterate(mid, end)); 
      } 
     } 
    } 
} 
+0

Parece que está funcionando como está diseñado. Está solicitando el paralelismo de 1, pero luego está agregando dos tareas en invokeAll. Pero no soy un experto en esto, así que podría estar equivocado. –

+0

He escuchado esto antes de otras personas, que establecer la cantidad de hilos en "uno más" corrige las cosas. –

+0

Re: Jochen - Según entiendo el marco, deberíamos poder agregar un número arbitrario de tareas, independientemente del nivel de paralelismo (número de hilos). Por ejemplo, podríamos subdividir recursivamente una tarea grande en 256 tareas pequeñas separadas, pero deberíamos poder ejecutar ese algoritmo en una máquina con menos de 256 procesadores. Además, el punto muerto no es inmediato (como era de esperar si 2 tareas/1 hilo eran ilegales, sino que es después de una cantidad impredecible de iteraciones. Pero también soy relativamente nuevo con FJ, así que podría estar malentendiendo) – AaronD

Respuesta

3

parece un error en el ForkJoinPool. todo lo que puedo ver en el uso de la clase se ajusta a su ejemplo. la única otra posibilidad podría ser que una de sus tareas arroje una excepción y fallezca de manera anormal (aunque eso aún debería manejarse).

+1

Esto fue en hecho un error en ForkJoinPool. Contrariamente a @axtavt, es reproducible en JDK 1.7, así como en JDK 1.6 + jsr166y. Discutí esto con Doug Lea en un foro separado, y llegó a la conclusión de que ForkJoinPool estaba terminando prematuramente el hilo de trabajo. El arreglo ahora está registrado y disponible en http://gee.cs.oswego.edu/dl/concurrency-interest/index.html, y debería estar disponible en breve en las compilaciones de OpenJDK 1.7. – AaronD

+0

muy buena captura! – jtahlborn

Cuestiones relacionadas