Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

[C++/MFC] : Use a Thread Delegator for your threads

0.00/5 (No votes)
19 Oct 2010CPOL 9.4K  
I always use a somewhat different approach, here is a classconsumer that has embedded the thread call in a member function,the member function runs a virtual call, hence the derived classesmay implement functionality as well as passing arguments asmember data of the class. Maybe you're...
I always use a somewhat different approach, here is a class
"consumer" that has embedded the thread call in a member function,
the member function runs a virtual call, hence the derived classes
may implement functionality as well as passing arguments as
member data of the class. Maybe you're interested to add such a method
to embed a thread call in a class to the spectrum of alternatives:

--- header ---
#ifndef CONSUMER_H
#define CONSUMER_H
#include <afx.h>
#include <afxwin.h>
#include <set>
using namespace std;
typedef set<CWnd*> ObserverListConsumerDef;
class CConsumer
{
public:
   CConsumer(void);
   virtual ~CConsumer(void);
// Thread Interface
public:
   bool Start(void); // Start the thread
   bool Stop (void) { m_bStop = true; return true; } // Stop  the thread
   bool Abort(void); // Stop the thread (brute force kill it)
   bool IsRunning() { return m_bIsRunning; }; // Is the thread running
   bool IsSuccess() { return m_bSuccess; }; // Was the run successful ?
   virtual bool Execute() = 0; // Override to provide functionality
// the thread itself
protected:
   static UINT ThreadFunc(LPVOID pVoid)
   {
      return( ((CConsumer*) pVoid)->LocalThreadFunc() );
   }
   UINT LocalThreadFunc(void);
   bool  m_bIsRunning;
   bool  m_bSuccess;
   bool  m_bStop;
   CWinThread* m_pThread;
   HANDLE      m_hThread;
// Observer Windows
public:
   void SetObserver(CWnd *pWnd);
   void DelObserver(CWnd *pWnd);
protected:
   ObserverListConsumerDef m_ObserverList;
   void SendMessageToObs(UINT nMsg, WPARAM wP, LPARAM lP);
};
#endif  // ! defined (CONSUMER_H)

--- header ---

--- body ---
#include "StdAfx.h"
#include "Consumer.h"

#ifndef THREADMESSAGES_H
#define THREADMESSAGES_H
#define WM_MSG_START     (WM_USER + 0x0101)
#define WM_MSG_ABORTED   (WM_USER + 0x0102)
#define WM_MSG_ENDED     (WM_USER + 0x0103)
#define WM_MSG_PROGRESS  (WM_USER + 0x0104)
#define WM_MSG_DATA      (WM_USER + 0x0105)
#endif  // ! defined (THREADMESSAGES_H)

CConsumer::CConsumer(void)
{
   m_bIsRunning = false;
   m_bSuccess = false;
   m_bStop = false;
   m_pThread = NULL;
   m_hThread = NULL;
}
CConsumer::~CConsumer(void)
{
}
// Thread Interface
// Start the thread
bool CConsumer::Start(void)
{
   if(m_bIsRunning)
      return false;
   TCHAR CALLER[] = _T("CConsumer::Start");
   // reset the success flag
   m_bSuccess = false;
   m_bStop = false;
   m_bIsRunning = true;
   m_pThread = AfxBeginThread ((AFX_THREADPROC) ThreadFunc, this,
      THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
   if(!m_pThread)
   {
      m_bIsRunning = false;
      m_pThread = NULL;
      m_hThread = NULL;
      return false;
   }
   // get the thread handle
   ::DuplicateHandle (GetCurrentProcess(), m_pThread->m_hThread, 
      GetCurrentProcess(), &m_hThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
   SendMessageToObs(WM_MSG_START,NULL,NULL);
   // resume the suspended thread
   m_pThread->ResumeThread();
   return true;
}
// Stop the thread
bool CConsumer::Abort(void)
{
   if(!m_bIsRunning)
      return true;
   m_bStop = true;
   Sleep(100);
   TCHAR CALLER[] = _T("CConsumer::Abort");
   // Terminate brutally the thread.
   ::TerminateThread (m_hThread, 0);
   // Check the thread termination
   DWORD dwExitCode;
   ::GetExitCodeThread (m_hThread, &dwExitCode);
   if ( STILL_ACTIVE == dwExitCode )
   {  // The thread is still running.
      Sleep(1000);
      // Try again to kill it
      ::TerminateThread (m_hThread, 0);
      // Check the thread termination
      DWORD dwExitCode2;
      ::GetExitCodeThread (m_hThread, &dwExitCode2);
      if ( STILL_ACTIVE == dwExitCode2 )
      {
         return false;
      }
   }
   else
   {
      // The thread has terminated. Close the thread handle.
      ::CloseHandle (m_hThread);
   }
   SendMessageToObs(WM_MSG_ABORTED,NULL,NULL);
   m_bIsRunning = false;
   m_pThread = NULL;
   m_hThread = NULL;
   return true;
}
// the thread itself
UINT CConsumer::LocalThreadFunc(void)
{
   TCHAR CALLER[] = _T("CConsumer::LocalThreadFunc");
   // do work
   m_bSuccess = Execute();
   m_bIsRunning = false;
   SendMessageToObs(WM_MSG_ENDED,NULL,NULL);
   if ( !m_bSuccess )
      return 1; // error during simulation
   return 0; // success
}
void CConsumer::SetObserver(CWnd *pWnd)
{
   m_ObserverList.insert(pWnd);
}
void CConsumer::DelObserver(CWnd *pWnd)
{
   ObserverListConsumerDef::iterator it = m_ObserverList.find(pWnd);
   if ( it != m_ObserverList.end() )
      m_ObserverList.erase(it);
}
void CConsumer::SendMessageToObs(UINT nMsg, WPARAM wP, LPARAM lP)
{
   CWnd* pWnd = NULL;
   ObserverListConsumerDef::iterator it = m_ObserverList.begin();
   while ( it != m_ObserverList.end() )
   {
      pWnd = NULL;
      pWnd = *it;
      if (pWnd)
         pWnd->SendMessage(nMsg, wP, lP);
      it++;
   }
}

--- body ---

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)