Threads And Timers






4.60/5 (10 votes)
Jan 27, 2004
1 min read

164745

4199
Adding a WM_TIMER message to CWinThreads.
Introduction
In this project and in the source files, there is a base class to CWinThread
class that will provide you with WM_TIMER
messages to your threads. Since WM_TIMER
messages are reserved for window objects only, this is a bit tricky to perform. I did this because I was in need of threads that could react to timers but I had lots of threads (100's) to manage and they all read there configuration from the database and set timers based on that configuration. Some threads had 1 timer and other threads had 100's of timers. I needed a way to manage all these timers and events.
Using the code
This class is derived from the standard MFC CWinThread
class. m_autoremove
will remove all the timers outstanding if you don't. You can turn it off by setting the m_autoremove
to false
. There are 2 methods AddTimer()
and RemoveTimer()
. Simple!
// WinTimerThread.h class CWinTimerThread : public CWinThread { public: DECLARE_DYNCREATE(CWinTimerThread) // CWinTimerThread(); ~CWinTimerThread(); // bool m_autoremove; // UINT_PTR AddTimer(UINT uElapse); BOOL RemoveTimer(UINT_PTR idEvent); };
// WinTimerThread.cpp ... // Static declarations static CMapPtrToPtr g_MapTimerID_TO_CWinThreadPtr; static void CALLBACK TimerProc( HWND hwnd, // handle to window UINT uMsg, // WM_TIMER message UINT_PTR idEvent, // timer identifier DWORD dwTime // current system time ) { CWinThread* pThread; if (g_MapTimerID_TO_CWinThreadPtr.Lookup((void *) idEvent, (void*&) pThread)) { pThread->PostThreadMessage(WM_TIMER, idEvent, dwTime); } } // Class IMPLEMENT_DYNCREATE(CWinTimerThread, CWinThread) CWinTimerThread::CWinTimerThread() { m_autoremove = true; } CWinTimerThread::~CWinTimerThread() { // check if autoremove is activated if (!m_autoremove) return; // declare local variables POSITION pos; UINT_PTR idEvent; CWinThread* pThread; //get the starting point in the list of timer events pos = g_MapTimerID_TO_CWinThreadPtr.GetStartPosition(); //loop while there are list items while (pos) { // get timer event entry g_MapTimerID_TO_CWinThreadPtr.GetNextAssoc(pos, (void *&) idEvent, (void*&) pThread); // check if the idevent is refering to this object if (pThread == this) { RemoveTimer(idEvent); } } } UINT_PTR CWinTimerThread::AddTimer(UINT uElapse) { UINT_PTR idEvent; idEvent = ::SetTimer(NULL, NULL, uElapse, (TIMERPROC) TimerProc); g_MapTimerID_TO_CWinThreadPtr.SetAt((void *) idEvent, this); return idEvent; } BOOL CWinTimerThread::RemoveTimer(UINT_PTR idEvent) { ::KillTimer(NULL, idEvent); return g_MapTimerID_TO_CWinThreadPtr.RemoveKey((void *) idEvent); }
Below is how to use the new CWinTimerThread
.
// MyThread.h #include "WinTimerThread.h" #if !defined(MYTHREAD_H) #define MYTHREAD_H #pragma once class CMyThread : public CWinTimerThread { public: DECLARE_DYNCREATE(CMyThread) // CMyThread(); ~CMyThread(); virtual BOOL InitInstance(); virtual int ExitInstance(); void SetLogWindow(CWnd* pWnd); protected: // CWnd* m_pLogWnd; // void LogMessage(CString& logmsg); void OnTimer(WPARAM idEvent, LPARAM dwTime); // DECLARE_MESSAGE_MAP()}; #endif // MYTHREAD_H
Notice that all you have to do is call AddTimer()
anywhere in the thread and specify the amount of milliseconds, and you're done. The clean up is done for you so you don't even have to worry about it.
// MyThread.cpp // #include "stdafx.h" #include "MyThread.h" #ifdef _DEBUG #define new DEBUG_NEW #endif IMPLEMENT_DYNCREATE(CMyThread, CWinTimerThread) CMyThread::CMyThread() { } CMyThread::~CMyThread() { } BEGIN_MESSAGE_MAP(CMyThread, CWinTimerThread) ON_THREAD_MESSAGE(WM_TIMER, OnTimer) END_MESSAGE_MAP() BOOL CMyThread::InitInstance() { ... // AddTimer(1000); return TRUE; } ...
Points of Interest
Posting the WM_TIMER
message to the thread should be safe since the numeric value is 0x113, well below WM_USER = 0x400
. This is very compatible to the original SetTimer()
, KillTimer()
and OnTimer(idEvent, dwTime)
.
Also note that the message to the thread is ON_THREAD_MESSAGE()
not the ON_MESSAGE()
macro.
History
Version 1.0