Pattern Name: EmbarrassinglyParallel

AlgorithmStructure Design Space

Supporting Document: Examples

 

Vector Addition:

The following code uses an OpenMP parallel loop directive to perform vector addition.

    !$OMP PARALLEL DO
        DO I = 1, N
            C(I) = A(I) + B(I)
        ENDDO
    !$OMP END PARALLEL DO

Varying-Length Tasks, Master-Worker Implementation:

The following code uses a task queue and master-worker approach to solving the stated problem. We implement the task queue as an instance of the SharedQueue pattern.

The master process, shown below, initializes the task queue, representing each task by an integer. It then uses the ForkJoin pattern to create the worker processes or threads and wait for them to complete. When they have completed, it consumes the results.

    #define Ntasks  500              /* Number of tasks       */
    #define Nworkers  5              /* Number of workers     */

    SharedQueue task_queue;          /* task queue            */
    Results Global_results[Ntasks];  /* array to hold results */

    void master()
    {
       void Worker();

       // Create and initialize shared data structures 
       task_queue = new SharedQueue();
       for (int i = 0; i < N; i++)
          enqueue(&task_queue, i);

       // Create Nworkers threads executing function Worker()
       ForkJoin (Nworkers, Worker);

       Consume_the_results (Ntasks);
    }

The worker process, shown below, loops until the task queue is empty. Every time through the loop, it grabs the next task, does the indicated work (storing the results into a global results array). When the task queue is empty, the worker terminates.

    void Worker()
    {
      int i;
      Result res;

      While (!empty(task_queue) {
         i = dequeue(task_queue);
         res = do_lots_of_work(i);
         Global_results[i] = res;
      }
    }

Note that we ensure safe access to the key shared variable (the task queue) by implementing it using patterns from the SupportingStructures space. Note also that the overall organization of the master process is an instance of the ForkJoin pattern.

Varying-Length Tasks, SPMD Implementation:

As an example of implementing this pattern without a master process, consider the following sample code using the TCGMSG message-passing library (described in [Harrison91]). The library has a function called NEXTVAL that implements a global counter. An SPMD program could use this construct to create a task-queue program as shown below.

    While (itask = NEXTVAL() < Number_of_tasks){
        do_lots_of_work(itask);
    }