Skip to content

Instantly share code, notes, and snippets.

@alexandruc
Created August 28, 2011 19:17
Show Gist options
  • Save alexandruc/1177079 to your computer and use it in GitHub Desktop.
Save alexandruc/1177079 to your computer and use it in GitHub Desktop.
Dispatcher class: asynchronousely dispathces messages
#pragma once
#include <windows.h>
#include <queue>
/**
* Default deallocation function (no deallocation)
*/
typedef void (*noDeleteFunction)(...);
/** \p Dispatcher class: asynchronousely dispathces messages
* \t Template instantiation:
* @param ClassPtr Pointer to class from which the fPtr method will be called
* @param fPtr Pointer to class method which will be used for dispatching messages
* @param MsgType Type of the message to be dispatched
* @param pfMsgDealloc Pointer to function which will be called to deallocate messages (in case of usage of complex types)
*/
template <class ClassPtr, class fPtr, class MsgType, typename pfMsgDealloc=noDeleteFunction>
class Dispatcher
{
public:
/**
* Default constructor
*/
Dispatcher(void): m_csLock(),
m_messageQueue(),
m_pf(0),
m_pClass(0),
m_thHandle(0),
m_thSyncEvent(0),
m_bKillTh(0),
m_pfDelete(0),
m_bInitialized(false)
{
InitializeCriticalSection(&m_csLock);
};
/**
* Default destructor
*/
~Dispatcher(void)
{
DeleteCriticalSection(&m_csLock);
};
/**
* Method used to insert messages in the dispatcher queue
* @param message Message to be dispatched
*/
void dispatch(MsgType message)
{
EnterCriticalSection(&m_csLock);
//add message for decoupling
m_messageQueue.push(message);
SetEvent(m_thSyncEvent); //let the thread process the event
LeaveCriticalSection(&m_csLock);
};
/**
* Method used to initialize the dispatcher
* @param pClass Pointer to object from which the class method will be called
* @param pf Pointer to member function which will be called to process the message
* @param pfMsgDealloc Pointer to function used to deallocate the message
* @return true for successful initialization, false otherwise
*/
bool initializeDispatcher(ClassPtr pClass, fPtr pf, pfMsgDealloc pfDelete=0)
{
EnterCriticalSection(&m_csLock);
bool retVal = true;
DWORD dwThreadId = 0;
if(!m_bInitialized)
{
m_pClass = pClass;
m_pf = pf;
m_pfDelete = pfDelete;
m_thSyncEvent = CreateEvent(NULL, TRUE /* man reset */, FALSE /* non-signaled first */, L"NotificationThreadEvent");
if(m_thSyncEvent == NULL)
{
printf("Dispatcher::initializeDispatcher: failed to create dispatcher event \n");
retVal = false;
}
if(retVal)
{
m_thHandle = CreateThread(NULL, NULL, notificationThProcWrapper, this, NULL, &dwThreadId);
if(m_thHandle == NULL)
{
printf("Dispatcher::initializeDispatcher: failed to create dispatcher thread \n");
retVal = false;
}
}
if(retVal)
{
m_bInitialized = true;
}
}
LeaveCriticalSection(&m_csLock);
return retVal;
};
/**
* Unitializes dispatcher - deallocates resources
*/
void uninitializeDispatcher()
{
EnterCriticalSection(&m_csLock);
//uninitialize thread
m_bKillTh = true;
SetEvent(m_thSyncEvent);
WaitForSingleObject(m_thHandle, INFINITE);
//close handles
CloseHandle(m_thHandle);
CloseHandle(m_thSyncEvent);
//clear the queue (objects should have a proper destructor implemented)
while(!m_messageQueue.empty())
{
MsgType message = m_messageQueue.front();
m_messageQueue.pop();
deallocateMessage(message);
}
m_bInitialized = false;
LeaveCriticalSection(&m_csLock);
};
/**
* Thread procedure
*/
void notificationThProc()
{
while(true)
{
DWORD dwWaitVal = 0;
dwWaitVal = WaitForSingleObject(m_thSyncEvent, INFINITE);
if(m_bKillTh)
{
break;
}
switch(dwWaitVal)
{
case WAIT_TIMEOUT:
{
}
case WAIT_OBJECT_0:
{
EnterCriticalSection(&m_csLock);
if(m_messageQueue.empty())
{
ResetEvent(m_thSyncEvent); //no more data -> stop thread
}
else
{
MsgType& message = m_messageQueue.front();
if(m_pf != 0)
{
//process the message
(m_pClass->*m_pf)(*message);
//remove message from queue
m_messageQueue.pop();
//deallocate the message
deallocateMessage(message);
}
}
LeaveCriticalSection(&m_csLock);
}
break;
default:
{
}
break;
}
}
};
private:
/**
* Deallocation method - will call pointer to deallocation function
* @param message Message object to be deallocated
*/
void deallocateMessage(MsgType& message)
{
if(m_pfDelete != 0)
{
m_pfDelete(message);
}
};
/**
* Wrapper of the notification thread
* @param param Parameter sent to thread method
*/
static DWORD WINAPI notificationThProcWrapper(LPVOID param)
{
Dispatcher<ClassPtr, fPtr, MsgType>* obj = reinterpret_cast< Dispatcher<ClassPtr, fPtr, MsgType>* >(param);
obj->notificationThProc();
return 0;
};
private:
CRITICAL_SECTION m_csLock; /**< synchronization lock */
std::queue<MsgType> m_messageQueue; /**< queue to hold the notifications */
fPtr m_pf; /**< pointer to function */
ClassPtr m_pClass; /**< pointer to the class object whose function will be called */
HANDLE m_thHandle; /**< Handle of the notification thread */
HANDLE m_thSyncEvent; /**< Handle of the event which will synchronize the thread */
bool m_bKillTh; /**< Guard used to safely close the dispatcher thread */
pfMsgDealloc m_pfDelete; /**< function used to deallocate messages (in case it's needed - complex types) */
bool m_bInitialized; /**< Guard to check if this instance of the dispatcher is initialized */
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment