// Win32++ Version 7.2 // Released: 5th AUgust 2011 // // David Nash // email: dnash@bigpond.net.au // url: https://sourceforge.net/projects/win32-framework // // // Copyright (c) 2005-2011 David Nash // // Permission is hereby granted, free of charge, to // any person obtaining a copy of this software and // associated documentation files (the "Software"), // to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, // merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom // the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice // shall be included in all copies or substantial portions // of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE // OR OTHER DEALINGS IN THE SOFTWARE. // //////////////////////////////////////////////////////// // The CThread class simplifies the use of threads with Win32++. // To use threads in your Win32++ application, inherit a class from // CThread, and override InitInstance. When your class is instanciated, // a new thread is started, and the InitInstance function is called to // run in the new thread. // If your thread is used to run one or more windows, InitInstance should // return TRUE, causing the MessageLoop function to be called. If your // thread doesn't require a MessageLoop, it should return FALSE. Threads // which don't run a message loop as sometimes referred to as "worker" threads. // Note: It is your job to end the thread before CThread ends! // To end a thread with a message loop, use PostQuitMessage on the thread. // To end a thread without a message loop, set an event, and end the thread // when the event is received. // Hint: It is never a good idea to use things like TerminateThread or ExitThread to // end your thread. These represent poor programming techniques, and are likely // to leak memory and resources. // More Hints for thread programming: // 1) Avoid using SendMessage between threads, as this will cause one thread to wait for // the other to respond. Use PostMessage between threads to avoid this problem. // 2) Access to variables and resources shared between threads need to be made thread safe. // Having one thread modify a resouce or variable while another thread is accessing it is // a recipe for disaster. // 3) Thread Local Storage (TLS) can be used to replace global variables to make them thread // safe. With TLS, each thread gets its own copy of the variable. // 4) Critical Sections can be used to make shared resources thread safe. // 5) Window messages (including user defined messages) can be posted between GUI threads to // communicate information between them. // 6) Events (created by CreateEvent) can be used to comunicate information between threads // (both GUI and worker threads). // 7) Avoid using sleep to synchronise threads. Generally speaking, the various wait // functions (e.g. WaitForSingleObject) will be better for this. // About Threads: // Each program that executes has a "process" allocated to it. A process has one or more // threads. Threads run independantly of each other. It is the job of the operating system // to manage the running of the threads, and do the task switching between threads as required. // Systems with multiple CPUs will be able to run as many threads simultaneously as there are // CPUs. // Threads behave like a program within a program. When the main thread starts, the application // runs the WinMain function and ends when WinMain ends. When another thread starts, it too // will run the function provided to it, and end when that function ends. #ifndef _WIN32XX_WINTHREAD_H_ #define _WIN32XX_WINTHREAD_H_ #include namespace Win32xx { ////////////////////////////////////// // Declaration of the CThread class // class CThread { public: CThread(); CThread(LPSECURITY_ATTRIBUTES pSecurityAttributes, unsigned stack_size, unsigned initflag); virtual ~CThread(); // Overridables virtual BOOL InitInstance(); virtual int MessageLoop(); // Operations HANDLE GetThread() const; int GetThreadID() const; int GetThreadPriority() const; DWORD ResumeThread() const; BOOL SetThreadPriority(int nPriority) const; DWORD SuspendThread() const; private: CThread(const CThread&); // Disable copy construction CThread& operator = (const CThread&); // Disable assignment operator void CreateThread(LPSECURITY_ATTRIBUTES pSecurityAttributes, unsigned stack_size, unsigned initflag); static UINT WINAPI StaticThreadCallback(LPVOID pCThread); HANDLE m_hThread; // Handle of this thread UINT m_nThreadID; // ID of this thread }; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ namespace Win32xx { /////////////////////////////////////// // Definitions for the CThread class // inline CThread::CThread() : m_hThread(0), m_nThreadID(0) { CreateThread(0, 0, CREATE_SUSPENDED); } inline CThread::CThread(LPSECURITY_ATTRIBUTES pSecurityAttributes, unsigned stack_size, unsigned initflag) : m_hThread(0), m_nThreadID(0) { // Valid argument values: // pSecurityAttributes Either a pointer to SECURITY_ATTRIBUTES or 0 // stack_size Either the stack size or 0 // initflag Either CREATE_SUSPENDED or 0 CreateThread(pSecurityAttributes, stack_size, initflag); } inline CThread::~CThread() { // A thread's state is set to signalled when the thread terminates. // If your thread is still running at this point, you have a bug. if (0 != WaitForSingleObject(m_hThread, 0)) TRACE(_T("*** Error *** Ending CThread before ending its thread\n")); // Close the thread's handle ::CloseHandle(m_hThread); } inline void CThread::CreateThread(LPSECURITY_ATTRIBUTES pSecurityAttributes, unsigned stack_size, unsigned initflag) { // NOTE: By default, the thread is created in the default state. m_hThread = (HANDLE)_beginthreadex(pSecurityAttributes, stack_size, CThread::StaticThreadCallback, (LPVOID) this, initflag, &m_nThreadID); if (0 == m_hThread) throw CWinException(_T("Failed to create thread")); } inline HANDLE CThread::GetThread() const { assert(m_hThread); return m_hThread; } inline int CThread::GetThreadID() const { assert(m_hThread); return m_nThreadID; } inline int CThread::GetThreadPriority() const { assert(m_hThread); return ::GetThreadPriority(m_hThread); } inline BOOL CThread::InitInstance() { // Override this function to perform tasks when the thread starts. // return TRUE to run a message loop, otherwise return FALSE. // A thread with a window must run a message loop. return FALSE; } inline int CThread::MessageLoop() { // Override this function if your thread needs a different message loop return GetApp()->MessageLoop(); } inline DWORD CThread::ResumeThread() const { assert(m_hThread); return ::ResumeThread(m_hThread); } inline DWORD CThread::SuspendThread() const { assert(m_hThread); return ::SuspendThread(m_hThread); } inline BOOL CThread::SetThreadPriority(int nPriority) const { assert(m_hThread); return ::SetThreadPriority(m_hThread, nPriority); } inline UINT WINAPI CThread::StaticThreadCallback(LPVOID pCThread) // When the thread starts, it runs this function. { // Get the pointer for this CMyThread object CThread* pThread = (CThread*)pCThread; if (pThread->InitInstance()) return pThread->MessageLoop(); return 0; } } #endif // #define _WIN32XX_WINTHREAD_H_