Image Component Library (ICL)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Classes | Public Types | Public Member Functions
icl::utils::MultiThreader Class Reference

Utility class for parallelizing algorithms. More...

#include <MultiThreader.h>

Inheritance diagram for icl::utils::MultiThreader:
icl::utils::ShallowCopyable< MultiThreaderImpl, MultiThreaderImplDelOp >

List of all members.

Classes

class  Work
 plugin class for work packages performed parallel More...

Public Types

typedef std::vector< Work * > WorkSet
 set of work packages, that should be performed parallel

Public Member Functions

 MultiThreader ()
 Empty (null) constructor.
 MultiThreader (int nThreads)
 Default constructor with defined set of working threads.
void operator() (WorkSet &ws)
 applying operator (performs each Work* element of ws parallel)
int getNumThreads () const
 returns the number of WorkThreads

Detailed Description

Utility class for parallelizing algorithms.

Overview

The Multithreader class provides a simple interface to parallelize algorithms. To achieve a multi-threaded implementation of an algorithm, you have to split the computation loop into N parts (Work-Packages or short Work). Each of this Works will be computed in a single thread internally when given to the apply operator of the MultiThreader.

Please note This tool was written before openmp became popular and part of compilers. Today we recommend to use openmp rather then the Multithreader class.

Example

The following example explains how to parallelize a simple function-call

        #include <ICLQt/Quick.h>
        #include <cmath>
        #include <ICLUtils/MultiThreader.h>
        
        // a simple function calculating the l2 norm on a data array
        void l2norm_vec(float *dataStart,float *dataEnd, int dimPerElem, float *dst){
          for(;dataStart<dataEnd;dst++){
            float accu = 0; 
            for(int i=0;i<dimPerElem;i++,dataStart++){
              accu += (*dataStart) * (*dataStart);
            }
            *dst = sqrt(accu);
          }
        }
        
        // Wrapper for this function (implementing the MultiThreader::Work interface)
        struct L2NormWork : public MultiThreader::Work{
          L2NormWork(float *dataStart,float *dataEnd, int dimPerElem, float *dst):
            dataStart(dataStart),dataEnd(dataEnd),dimPerElem(dimPerElem),dst(dst){
          }
          float *dataStart,*dataEnd;
          int dimPerElem;
          float *dst;
        
          // interface function -> calls the wrapped function
          virtual void perform(){
            l2norm_vec(dataStart,dataEnd,dimPerElem,dst);
          }
        };
        
  
        int main(){
          // creating some really BIG data array
          const int DIM = 10000000;
          // dimension of each data element
          int dim = 100;
          float *data = new float[DIM];
          float *dst = new float[DIM/dim];
        
          // apply single threaded 100 times:
          tic();
          for(int i=0;i<100;i++){
            l2norm_vec(data,data+DIM,dim,dst);
          }
          toc();  
        
          //--- multi threaded part --------------------------
        
          // create a MultiThreader with 2 Threads
          MultiThreader mt(2);
        
          // create a WorkSet with 2 work packages
          MultiThreader::WorkSet ws(2);
        
          // 1st package: first half of the array
          ws[0] = new L2NormWork(data,data+DIM/2,dim,dst);
        
          // 2nd package: second half of the array
          ws[1] = new L2NormWork(data+DIM/2,data+DIM,dim,dst+DIM/2);
        
          // apply 100 times multi-threaded in 2 Threads
          tic();
          for(int i=0;i<100;i++){
            mt(ws);
          }
          toc();
        
          // release the work instances
          delete ws[0];
          delete ws[1];
          delete [] data;
          delete [] dst;
          return 0;
        }

Result

The following benchmark results were obtained:

Usability

However, the MultiThreader provides a powerful interface for parallelizing code, it is still a bit inconvenient to use. The Example above has shown, that the programmer has to write about 10 additional line for the function wrapper and another 4 lines to create the WorkSet and to fill the MultiThreader instance with it.
For more convenience some additional high level classes and functions should be implemented. For instance the SplittedUnaryop class of the ICLFilter package, which provides a top level interface for parallelizing unary operators (class interface UnaryOp)


Member Typedef Documentation

set of work packages, that should be performed parallel


Constructor & Destructor Documentation

Empty (null) constructor.

Default constructor with defined set of working threads.


Member Function Documentation

returns the number of WorkThreads

void icl::utils::MultiThreader::operator() ( WorkSet ws)

applying operator (performs each Work* element of ws parallel)


The documentation for this class was generated from the following file:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines