1.以一個C++對象啟動一個線程
Q:如何以一個C++成員函數當做線程的起始函數。
錯誤的例子
#include <windows.h>#include <stdio.h>#include <process.h>typedef unsigned (WINAPI *PBEGINTHREADEX_THREADFUNC)( LPVOID lpThreadParameter );typedef unsigned *PBEGINTHREADEX_THREADID;class ThreadObject{public: ThreadObject(); void StartThread(); virtual DWORD WINAPI ThreadFunc(LPVOID param); void WaitForExit();private: HANDLE m_hThread; DWORD m_ThreadId;};ThreadObject::ThreadObject(){ m_hThread = NULL; m_ThreadId = 0;}void ThreadObject::StartThread(){ m_hThread = (HANDLE)_beginthreadex(NULL, 0, (PBEGINTHREADEX_THREADFUNC)ThreadFunc, 0, 0, (PBEGINTHREADEX_THREADID)&m_ThreadId ); if (m_hThread) { printf("Thread launched\n"); }}void ThreadObject::WaitForExit(){ WaitForSingleObject(m_hThread, INFINITE); CloseHandle(m_hThread);}DWORD WINAPI ThreadObject::ThreadFunc(LPVOID param) //對類的成員函數預設有一個this參數{ // Do something useful ... return 0;}void main(){ ThreadObject obj; obj.StartThread(); obj.WaitForExit();}
正確的做法
為了以一個成員函數啟動一個線程,要麼使用靜態成員函數,要麼使用C函數,而非C++成員函數。這兩種
技術的本質是相同的,但是靜態成員函數的一個優點就是,它能夠處理類的private成員變數和protected
成員變數。
由一個成員函數來啟動一個線程範例:
#define WIN32_LEAN_AND_MEAN#include <stdio.h>#include <stdlib.h>#include <windows.h>#include <process.h>typedef unsigned (WINAPI *PBEGINTHREADEX_THREADFUNC)( LPVOID lpThreadParameter );typedef unsigned *PBEGINTHREADEX_THREADID;//// This ThreadObject is created by a thread// that wants to start another thread. All// public member functions except ThreadFunc()// are called by that original thread. The// virtual function ThreadMemberFunc() is// the start of the new thread.//class ThreadObject{public: ThreadObject(); void StartThread(); void WaitForExit(); static DWORD WINAPI ThreadFunc(LPVOID param);protected: virtual DWORD ThreadMemberFunc(); HANDLE m_hThread; DWORD m_ThreadId;};ThreadObject::ThreadObject(){ m_hThread = NULL; m_ThreadId = 0;}void ThreadObject::StartThread(){ m_hThread = (HANDLE)_beginthreadex(NULL, 0, (PBEGINTHREADEX_THREADFUNC) ThreadObject::ThreadFunc, (LPVOID)this, 0, (PBEGINTHREADEX_THREADID) &m_ThreadId ); if (m_hThread) { printf("Thread launched\n"); }}void ThreadObject::WaitForExit(){ WaitForSingleObject(m_hThread, INFINITE); CloseHandle(m_hThread);}//// This is a static member function. Unlike// C static functions, you only place the static// declaration on the function declaration in the// class, not on its implementation.//// Static member functions have no "this" pointer,// but do have access rights.//DWORD WINAPI ThreadObject::ThreadFunc(LPVOID param){ // Use the param as the address of the object ThreadObject* pto = (ThreadObject*)param; // Call the member function. Since we have a // proper object pointer, even virtual functions // will be called properly. return pto->ThreadMemberFunc();}//// This above function ThreadObject::ThreadFunc()// calls this function after the thread starts up.//DWORD ThreadObject::ThreadMemberFunc(){ // Do something useful ... return 0;}void main(){ ThreadObject obj; obj.StartThread(); obj.WaitForExit();}在C++中如何利用建構函式和解構函式寫一個比較安全的多線程程式,以及如何利用虛函數和多態等性質做出一個可互換的鎖定機制。在C++中封裝一個Critical sectionclass CriticalSection{public:CriticalSection();~CriticalSection();void Enter();void Leave();private:CRITICAL_SECTION m_CritSect;}CriticalSection::CriticalSection(){InitializeCriticalSection(&m_CritSect);}CriticalSection::~CriticalSection(){DeleteCriticalSection(&m_CritSect);}CriticalSection::Enter(){ EnterCriticalSection(&m_CritSect);}CriticalSection::Leave(){ LeaveCriticalSection(&m_CritSect);}在String類中使用CriticalSection類Class String{ public: String(); virtual ~String(); virtual void Set(char *str);int GetLength();private:CriticalSection m_Sync;char * m_pData;};String::String(){ m_pData=NULL;}String::~String(){m_Sync.Enter();delete []m_pData;m_Sync.Leave();}void String::Set(char *str){m_Sync.Enter();delete [] m_pData;m_pData=new char[::strlen(str)+1];::strcpy(m_pData,str);m_Sync.Leave();}int String::GetLength(){if(m_pData==NULL)return 0;m_Sync.Enter();int len=::strlen(m_pData);m_Sync.Leave();return len;}
這樣就可以聲明一個String變數,完全可以不瞭解Critical section,就可以獲得同步效果。
----建立抽象的同步化對象
class Lock{ public:Lock(CriticalSection *pCritsect);~Lock();private:CriticalSection *m_pCritical;};Lock::Lock(CriticalSection *pCritsect){m_pCritical=pCritsect;EnterCriticalSection(&m_pCritical);}Lock::~Lock(){LeaveCriticalSection(&m_pCritical);}
這個解構函式可以被自動調用,而critical section會被自動地解除鎖定。絕對不會忘記將critical
section解除鎖定。
-------建立可互換的Lock
class LockableObject{public: LockableObject() {}virtual ~ LockableObject(){}virtual void Lock()=0;virtual void UnLock()=0;};public CriticalSectionV2: public LockableObject{CriticalSectionV2();virtual ~CriticalSectionV2();virtual void Lock();virtual void UnLock();private:CRITICAL_SECTION m_CritSect;};CriticalSectionV2::CriticalSectionV2(){InitializeCriticalSection(&m_CritSect);}CriticalSectionV2::~CriticalSectionV2(){DeleteCriticalSection(&m_CritSect);}CriticalSectionV2::Lock(){ EnterCriticalSection(&m_CritSect);}CriticalSectionV2::UnLock(){LeaveCriticalSection(&m_CritSect);}建立一個極安全又簡單的Lockclass LockV2{public: LockV2(LockableObject *pLockable);~LockV2();private:LockableObject * m_pLockable;};LockV2::LockV2(LockableObject *pLockable){m_pLockable=pLockable;m_pLockable->Lock();}LockV2::~LockV2(){ m_pLockable->UnLock();}
上面用C++類取代Win32 API的直接調用
用安全又簡單的“Lock”重寫String 類
class StringV2{public:StringV2();virtual ~StringV2();virtual void Set(char * str);int getLength();private:CriticalSectionV2 m_Lockable;char * m_pData;};StringV2::StringV2(){ m_pData=NULL;}StringV2::~StringV2(){delete [] m_pData;}void StringV2::Set(char *str){LockV2 localLock(&m_Lockable);delete [] m_pData; m_pData=NULL;m_pData=new char[strlen(str)+1];strcpy(m_pData,str);}int String::GetLength(){ LockV2 localLock(&m_Lockable);if(m_pData==NULL)return 0;return ::strlen(m_pData);}
複製 搜尋 複製 搜尋