Worker Threads

The obsolete way

One solution, the antiquated and largely unused 16-bit Windows solution (but still used because it is "well known"), is to use PeekMessage, an API call that does not block when there is no message.

void CMyView::doInvert()
    {
     running = TRUE; 
     for(int x=y = 0; running && y < image.height; y++)
          for(int x = 0; running && x < image.width; x++)
              { /* change it */
               MSG msg;
               if(PeekMessage(&msg, AfxGetMainWnd()->m_hWnd,
                              0, 0, PM_REMOVE))
                   { /* handle it*/
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                   } /* handle it */
               changePixel(x, y);
              } /* change it */
    }

This is bad for several reasons. The most important one is that it puts, in the time-critical main loop, a function whose overhead is substantial. Now, instead of taking k minutes (whatever that was before) we might find the algorithm takes a significant multiple of that to complete. But while it is running, the GUI is still active. You could even, if you were not careful, fire off another thread to paint each green pixel purple. This Is Not A Good Idea.

The performance hack is simple: only poll occasionally. For example, if we assume that the images are roughly rectangular, we could change the code to

void CMyView::doInvert()
    {
     running = TRUE; 
     for(int y = 0; running && y < image.height; y++)
         { /* do one row */
          MSG msg;
          if(PeekMessage(&msg, AfxGetMainWnd()->m_hWnd,
                         0, 0, PM_REMOVE))
             { /* handle it*/
              TranslateMessage(&msg);
              DispatchMessage(&msg);
             } /* handle it */
 
          for(int x = 0; running && x < image.width; x++)
              { /* change it */
               changePixel(x, y);
              } /* change it */
         } /* do one row */
    }

Thus this tests only once per row, which can either be too often if the rows are short, or not often enough if the rows are long. The generalization, changing the test to

if(x % 10 == 0 && PeekMessage(...))

will work if the rows are too short.

There are some problems remaining; for example, if there is a modeless dialog active, you will notice that there is no IsDialogMessage call there to handle it. Oops. Nor, for that matter, is there code to handle ActiveX event notifications. Oops. And it presumes that you are writing in pure C, and doing the dispatch yourself. Life gets more complicated when you have to support the message maps and control paradigms of MFC. Oops, squared.

But why bother when there is a better way?

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“It works on my machine.” - Anonymous