The example code for the ImageResize application

The task that performs the actual image processing is this:
class TResizeTask: public TTaskDispatcher::TTask
{
    IMAGEDATA Src,   // the source image
              Dest;  // the destination
    int Start,       // the first line in the destination
        End,         // the last            -"-
        Magn;
  public:
    TResizeTask(IMAGEDATA &src, IMAGEDATA &dest, int start, int end, int magn): Src(src), Dest(dest), Start(start), End(end), Magn(magn) {
      }
    void Execute(); // the virtual Execute(), that performs the transformation
};

void TResizeTask::Execute()
{
  int psize = GetPixelSize(Src.Type);
  for (int y = Start; y <= End; ++y)
    for (int x = 0; x < Dest.Width; ++x) {              // go through the destination pixels
      void *dp = GetPixelAddr(Dest, x, y),              // dest. pixel address
           *sp = GetPixelAddr(Src, x / Magn, y / Magn); // source pixel, we just get the inversely magnified coordinate - no interpolation
      memcpy(dp, sp, psize);                            // O.K., copy the pixel value
      }
}

After loading the input image and preparing the image data, we can easily create the tasks:
  int start = 0,                           // first line of the chunk
      end = start + lines - 1;             // last line
  vector<TTaskDispatcher::TTask *> tasks;  // the tasks to be executed
  while (start < dest_bmp.Height) {        // go through the destination image
    end = start + lines - 1;
    if (end >= dest_bmp.Height)            // trim the last line if it doesn't fit into the destination
      end = dest_bmp.Height - 1;

    TTaskDispatcher::TTask *t = new TResizeTask(src, dest, start, end, magn); // create the task for the current chunk
    tasks.push_back(t);

    start += lines;
    }

To execute the tasks parallelly (and to measure the execution time) is as simple as this:
  TTaskDispatcher dp(threads); // create the dispatcher with the actual number of threads
  DWORD st = GetTickCount();
  dp.Execute(tasks);           // execute the tasks (as fast as we can...)
  DWORD et = GetTickCount(),

As one can clearly see, we don't have to do anything with the parallel execution, the parallel task coordination is completely up to the TaskDispatcher. For example if we configure it for one thread, the whole transformation runs as a single-treaded process (with a little overhead of the task coordination) - this makes for example the debugging easier.


Attila NAGY Last updated: 2016-10-05