MFC Multithreading Goes Object Oriented!

Have you ever tried doing simple multithreading under MFC? It is easy, but not very object oriented. The key is a function called AfxBeginThread. There are two overloaded versions of this function: one takes a simple function as an argument. The other requires you to derive an object from CWinThread (see Tip #23).

It is the one that takes a simple function that always bothers me. You have to make the function a global or class static function because the thread has no this pointer. But you can fake it, as I'll show you in this month's tip.

There are lots of arguments that AfxBeginThread can take, but in practice, you probably only need two of them: the name of your function, and an argument. The function should take a single LPVOID argument and return a UINT (even if you don't care about the argument or the return value.

But the problem is that the function has to be global or class static, so it doesn't have access to your member variables or methods. What a drag. One solution is to use the argument to pass a pointer to a block of data that the new thread needs.

But what about access to a C++ object? Well, why not use the argument to pass a this pointer? Then your thread function becomes just a stub to pass control to your object. Just be aware that MFC restricts how you can use certain objects in threads that didn't create them (see the Microsoft Help; do an index search for 'Tips' and select the article 'Multithreading: Programming Tips'.

Here is a simple stub function to move a thread to your document's Thread1 function:

static UINT mtstub1(LPVOID xthis)
  {
  CDoc *_this=(CDoc *)xthis; // use your document name here
  _this->Thread1();
  return 0;  // or return the return value of Thread1() if you want
  }

Then to set this thread up from within a member function, try:

  AfxBeginThread(mtstub1,this);

Be sure to define mtstub1 (or at least declare it) before you make the call to AfxBeginThread.