Java Fork / Join Does it work just like the C fork?

4

Discussing with a friend about a matrix calculation solution we are developing, the following question came up.

Does the Java Fork / Join Framework work just like C?

Reading a little, I could not understand C's work very well. Could anyone help me with this?

    
asked by anonymous 22.10.2015 / 15:24

2 answers

2

Fork is a function that is a system call. That is, it invokes the operating system to do some task that the user can not. In this case, the fork is used to create a new process on Unix-like systems, and this can only be done via fork.

When a process is created through the fork, we say that this new process is the child, and the parent process is the one that used the fork.

To use the process creation system call, simply write fork (), without passing any arguments. By doing so, the Operating System takes care of the rest, and returns a number. This number is the pid (process identification), and each process has a value other than pid, as if it were the RG, the identification of each process.

However, when storing this fork function return in a variable named pid of type pid_t , we see that this pid number has a special behavior:

Within the child process, pid has a value of 0.

Within the parent process, pid has the value of the child process.

A fork() returns a negative value if an error has occurred.

So, to create a program and differentiate the parent process from the child, we just have to test with this return value of fork() . First, we tested whether fork() was successful. Then we do if (pid == 0) , and this is only true in the child process. That is, everything inside this if will only be executed by the child process, the parent does not go into this conditional. And if this conditional test is false, it is because the process in force is the parent. Then, inside the else , we put what will be executed only in the parent process.

An example of how to implement a fork in C:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{
    int i;
    pid_t pid;

    if ((pid = fork()) < 0) /*Se ocorer um erro*/
    {
        perror("fork");
        exit(1);
    }

    /**O getpid() retorna o pid do processo em execução.**/
    if (pid == 0)
    {
        //O código aqui dentro será executado no processo filho
        printf("pid do Filho: %d\n", getpid());
    }
    else
    {
        //O código neste trecho será executado no processo pai
        printf("pid do Pai: %d\n", getpid());
    }

    printf("Esta regiao sera executada por ambos processos\n\n");
    scanf("%d", &i);
    exit(0);
}

The conclusion is that the goal of fork and create a child process from the parent process, and work with both simultaneously and using both the same variables or their own, so you can make your application can run more than one task.

PS: You need the two libraries sys/types.h and unistd.h of Unix, to be able to work with the fork.

Source.

    
23.10.2015 / 00:38
1

From the tutorial , it's a little different.

In C, when the fork is done, you have 2 processes, one parent and one child. Given the child's pid, the parent process can join when the child process ends.

In Java, the algorithm is similar, but the operation for the Operating System is different. The algorithm is

se (a parte de trabalho for pequena o suficiente)
   faça o que tem que fazer
caso contrário
   divida o meu trabalho em duas partes
   execute as duas partes e espere pelo resultado

Example taken from University of Washington :

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

class Sum extends RecursiveTask<Long> {
    static final int SEQUENTIAL_THRESHOLD = 5000;

    int low;
    int high;
    int[] array;

    Sum(int[] arr, int lo, int hi) {
        array = arr;
        low   = lo;
        high  = hi;
    }

    protected Long compute() {
        if(high - low <= SEQUENTIAL_THRESHOLD) {
            long sum = 0;
            for(int i=low; i < high; ++i) 
                sum += array[i];
            return sum;
         } else {
            int mid = low + (high - low) / 2;
            Sum left  = new Sum(array, low, mid);
            Sum right = new Sum(array, mid, high);
            left.fork();
            long rightAns = right.compute();
            long leftAns  = left.join();
            return leftAns + rightAns;
         }
     }

     static long sumArray(int[] array) {
         return ForkJoinPool.commonPool().invoke(new Sum(array,0,array.length));
     }
}

In this example, you make a sum of the elements of an Array. If the array has more than 5000 elements, the task is split. The compute method implements the described pseudo-code.

Sort example :

static class SortTask extends RecursiveAction {
    final long[] array; final int lo, hi;
    SortTask(long[] array, int lo, int hi) {
        this.array = array; this.lo = lo; this.hi = hi;
    }
    SortTask(long[] array) { this(array, 0, array.length); }
    protected void compute() {
        if (hi - lo < THRESHOLD)
            sortSequentially(lo, hi);
        else {
            int mid = (lo + hi) >>> 1;
            invokeAll(new SortTask(array, lo, mid),
                new SortTask(array, mid, hi));
            merge(lo, mid, hi);
        }
    }
    // implementation details follow:
   static final int THRESHOLD = 1000;
   void sortSequentially(int lo, int hi) {
       Arrays.sort(array, lo, hi);
   }
   void merge(int lo, int mid, int hi) {
       long[] buf = Arrays.copyOfRange(array, lo, mid);
       for (int i = 0, j = lo, k = mid; i < buf.length; j++)
           array[j] = (k == hi || buf[i] < array[k]) ?
               buf[i++] : array[k++];
   }
}

First you have to choose the type of Task . There are two options:

  • RecusiveTask : returns a result after fork
  • ActionTask : does not return a result after fork

Second you have to implement the compute method following the pseudo-algorithm, using invokeAll , compute , fork and join .

Finally, you have to use a thread pool called ForkJoinPool . I have seen at least two ways:

ForkJoinPool.commonPool().invoke(task);

or

ForkJoinPool pool = new ForkJoinPool();
pool.invoke(task);

At the bottom of the screen, java.util.Arrays.parallelSort uses Fork / Join API.

    
24.02.2017 / 14:55