Comunicación entre procesos

Comunicación entre procesos.

Las operaciones multiproceso pueden implicar que sea necesario comunicar información entre muchos procesos,

lo que obliga a la necesidad de utilizar mecanismos específicos de comunicación que ofrecerá Java o a diseñar alguno separado que evite los problemas que puedan aparecer.

En el ejemplo, el segundo proceso suele sobreescribir el resultado del primero, así que modificaremos el código del lanzador para que cada proceso use su propio fichero de resultados.

La clase Sumador se quedará así:

public class Sumador {

    public static int sumar(int n1, int n2){
        int resultado = 0;
        for (int i = n1; i <= n2; i ++){
            resultado = resultado + i;
        }
        return resultado;
    }
    public static void main(String[] args){

        int n1 = Integer.parseInt(args[0]);
        int n2 = Integer.parseInt(args[1]);
        int resultado = sumar(n1, n2);
        System.out.println(resultado);
    }
}

La clase Lanzador será:

import java.io.File;

public class Lanzador {
    public void lanzarSumador(Integer n1, Integer n2, String ficheroResultado){
        String clase = "Sumador";
        ProcessBuilder pb;
        try {
            pb = new ProcessBuilder(
                    "java",
                    clase,
                    n1.toString(),
                    n2.toString());

            pb.redirectError(new File("errores.txt"));
            pb.redirectOutput(new File(ficheroResultado));
            pb.start();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public static void main(String[] args){
        Lanzador l=new Lanzador();
        l.lanzarSumador(1, 5, "resultado1.txt");
        l.lanzarSumador(6, 10, "resultado2.txt");
        System.out.println("Ok");
    }
}

Cuando se lanza un programa desde un IDE (Idea, Eclipse, etc) no ocurre lo mismo que cuando se lanza desde el sistema operativo (GNU/Linux o Windows).

Eclipse trabaja con unos directorios predefinidos y puede ser necesario indicar a nuestro programa cual es la ruta donde hay que buscar algo.

En Eclipse usando el método .directory(new File("c:\\dir\\)) se puede indicar a Java donde está el archivo que se desea ejecutar.

Ejercicio

Crear un programa que permita parametrizar el lanzamiento de sumadores, que vuelque el contenido de las sumas en ficheros y que permita al programa principal recuperar las sumas de los ficheros parciales.

En el listado siguiente se muestra la clase Sumador:

public class Sumador {
    /** Suma todos los valores incluidos
     * entre dos valores
     * @param n1 Limite 1
     * @param n2 Limite 2
     * @return La suma de dichos valores
     */
    public static int sumar(int n1, int n2){
        int suma = 0;
        if (n1 > n2){
            int aux = n1;
            n1 = n2;
            n2 = aux;
        }
        for (int i = n1; i <= n2; i ++){
            suma = suma + i;
        }
        return suma;
    }

    public static void main(String[] args){
        int n1 = Integer.parseInt(args[0]);
        int n2 = Integer.parseInt(args[1]);
        int suma = sumar(n1, n2);
        System.out.println(suma);
        System.out.flush();
    }
}

En el listado siguiente se muestra la clase Main:

import java.io.*;

public class Main {

    static final int NUM_PROCESOS = 10;
    static final String PREFIJO_FICHEROS = "fichero";

    public static void lanzarSumador(int n1, int n2, String ficheroResultados) throws IOException {
        String comando;
        comando = "Sumador";
        File carpeta;
        //carpeta = new File("./out/production/ComunicacionProcesos/com/company/");
        carpeta = new File("./");
        File fichero = new File(ficheroResultados);
        File errores = new File("errores.txt");
        ProcessBuilder pb;
        pb = new ProcessBuilder("java",
                comando,
                String.valueOf(n1),
                String.valueOf(n2) );
        pb.directory(carpeta);
        pb.redirectOutput(fichero);
        pb.redirectError(errores);
        pb.start();
    }

    public static int getResultadoFichero(String nombreFichero){
        int suma = 0;
        try {
            FileInputStream fis = new FileInputStream(nombreFichero);
            InputStreamReader isr = new InputStreamReader(fis);
            BufferedReader br = new BufferedReader(isr);
            String linea = br.readLine();
            suma = Integer.valueOf(linea);
        } catch (FileNotFoundException e) {
            System.out.println("No se pudo abrir " + nombreFichero);
        } catch (IOException e) {
            System.out.println("No hay nada en " + nombreFichero);
        } finally {
            return suma;
        }
    }

    public static long getSumaTotal(int n){
        long sumaTotal = 0;

        for (int i = 1; i <= n; i ++){
            sumaTotal += getResultadoFichero(PREFIJO_FICHEROS + String.valueOf(i) );
        }
        return sumaTotal;
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        // write your code here










    }
}

Ejecución en consola:

javac Sumador.java
javac Main.java
java Main

Código del proyecto en Idea: ComunicacionProcesos

Mejora: Controlar la terminación de los diferentes procesos y esperar a que terminen todos (usando el método waitFor()) antes de leer los ficheros de resultados, en lugar de esperar 1.000 ms.

Deja una respuesta