CreateEvent的用法收藏新一篇: PreCreateWindow的作用和使用方法 | 舊一篇: VC中_T()的作用事件對象就像一個開關:它只有兩種狀態(tài)---開和關。當一個事件處于”開”狀態(tài),我們稱其為”有信號”否則稱為”無信號”??梢栽谝粋€線程的執(zhí)行函數(shù)中創(chuàng)建一個事件對象,然后觀察它的狀態(tài),如果是”無信號”就讓該線程睡眠,這樣該線程占用的CPU時間就比較少。 產(chǎn)生事件對象的函數(shù)如下: HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, // SD 參數(shù)說明:
注釋: 發(fā)表于 @ 2008年04月18日 13:30:00|評論(0)|編輯 新一篇: PreCreateWindow的作用和使用方法 | 舊一篇: VC中_T()的作用Visual C++中的多線程收藏新一篇: 特洛伊木馬(一) | 舊一篇: 用戶接口與作業(yè)調(diào)度以前,曾經(jīng)研究過了java中的多線程問題,特別是加鎖和同步問題,但是,在C++中,確沒有這么簡單了。由于C沒有提供像java里的線程類,一些同步的實現(xiàn)必須靠自己程序?qū)崿F(xiàn),稍顯復雜。一般來說,在C++里面創(chuàng)建和終止線程的函數(shù)為:_beginthread和_endthread兩個函數(shù),當然,也可以用CreateThread和ExitThread。具體的使用方式可以查看msdn。 那么,怎么樣實現(xiàn)加鎖與同步呢?可以使用createMutex函數(shù)以及createEvent方法等來實現(xiàn),具體可以參考下例: #include < iostream> #include < windows.h> using namespace std; #define BUFSIZE 5 int SharedBuffer[BUFSIZE]; int head,tail; int count; HANDLE hMutex; HANDLE hNotFullEvent, hNotEmptyEvent; void BB_Producer() { int i; for (i=20; i>=0; i--) { while(1) { WaitForSingleObject(hMutex,INFINITE); if (count == BUFSIZE) { // 緩沖區(qū)滿 ReleaseMutex(hMutex); // 等待直到緩沖區(qū)非滿 WaitForSingleObject(hNotFullEvent,INFINITE); continue; } // 得到互斥鎖且緩沖區(qū)非滿,跳出while循環(huán) break; } // 得到互斥鎖且緩沖區(qū)非滿,開始產(chǎn)生新數(shù)據(jù) cout << "Produce: " << i << endl; SharedBuffer[tail] = i; tail = (tail+1) % BUFSIZE; count++; ReleaseMutex(hMutex); // 結(jié)束臨界區(qū) PulseEvent(hNotEmptyEvent); // 喚醒消費者線程 } } void BB_Consumer() { int result; while (1) { WaitForSingleObject(hMutex,INFINITE); if (count == 0) { // 沒有可以處理的數(shù)據(jù) ReleaseMutex(hMutex); // 釋放互斥鎖且等待 // 等待直到緩沖區(qū)非空 WaitForSingleObject(hNotEmptyEvent,INFINITE); } else if (SharedBuffer[head] == 0) { cout << "Consumed 0: end of data" << endl; ReleaseMutex(hMutex); // 結(jié)束臨界區(qū) ExitThread(0); } else { // 獲得互斥鎖且緩沖區(qū)有數(shù)據(jù),開始處理 result = SharedBuffer[head]; cout << "Consumed: " << result << endl; head = (head+1) % BUFSIZE; count--; ReleaseMutex(hMutex); // 結(jié)束臨界區(qū) PulseEvent(hNotFullEvent); // 喚醒生產(chǎn)者線程 } } } void main() { HANDLE hThreadVector[2]; DWORD ThreadID; count = 0; head = 0; tail = 0; hMutex = CreateMutex(NULL,FALSE,NULL); hNotFullEvent = CreateEvent(NULL,TRUE,FALSE,NULL); hNotEmptyEvent = CreateEvent(NULL,TRUE,FALSE,NULL); hThreadVector[0] = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) BB_Producer, NULL, 0, (LPDWORD)&ThreadID); hThreadVector[1] = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) BB_Consumer, NULL, 0, (LPDWORD)&ThreadID); WaitForMultipleObjects(2,hThreadVector,TRUE,INFINITE); } 發(fā)表于 @ 2006年10月29日 19:54:00|評論(2)|編輯 新一篇: 特洛伊木馬(一) | 舊一篇: 用戶接口與作業(yè)調(diào)度Windows API一日一練(45)CreateEvent和SetEvent函數(shù)收藏新一篇: Windows API一日一練(46)EnterCriticalSection和LeaveCriticalSection函數(shù) | 舊一篇: Windows API一日一練(44)wsprintf函數(shù)當你創(chuàng)建一個線程時,其實那個線程是一個循環(huán),不像上面那樣只運行一次的。這樣就帶來了一個問題,在那個死循環(huán)里要找到合適的條件退出那個死循環(huán),那么是怎么樣實現(xiàn)它的呢?在Windows里往往是采用事件的方式,當然還可以采用其它的方式。在這里先介紹采用事件的方式來通知從線程運行函數(shù)退出來,它的實現(xiàn)原理是這樣,在那個死循環(huán)里不斷地使用WaitForSingleObject函數(shù)來檢查事件是否滿足,如果滿足就退出線程,不滿足就繼續(xù)運行。當在線程里運行阻塞的函數(shù)時,就需要在退出線程時,先要把阻塞狀態(tài)變成非阻塞狀態(tài),比如使用一個線程去接收網(wǎng)絡數(shù)據(jù),同時使用阻塞的SOCKET時,那么要先關閉SOCKET,再發(fā)送事件信號,才可以退出線程的。下面就來演示怎么樣使用事件來通知線程退出來。
函數(shù)CreateEvent聲明如下:
WINBASEAPI
__out
HANDLE
WINAPI
CreateEventA(
__in_opt LPSECURITY_ATTRIBUTES lpEventAttributes,
__in BOOL bManualReset,
__in BOOL bInitialState,
__in_opt LPCSTR lpName
);
WINBASEAPI
__out
HANDLE
WINAPI
CreateEventW(
__in_opt LPSECURITY_ATTRIBUTES lpEventAttributes,
__in BOOL bManualReset,
__in BOOL bInitialState,
__in_opt LPCWSTR lpName
);
#ifdef UNICODE
#define CreateEvent CreateEventW
#else
#define CreateEvent CreateEventA
#endif // !UNICODE
lpEventAttributes是事件的屬性。
bManualReset是指事件手動復位,還是自動復位狀態(tài)。
bInitialState是初始化的狀態(tài)是否處于有信號的狀態(tài)。
lpName是事件的名稱,如果有名稱,可以跨進程共享事件狀態(tài)。
調(diào)用這個函數(shù)的例子如下:
#001 #pragma once
#002
#003 //線程類。
#004 //蔡軍生 2007/09/23 QQ:9073204
#005 class CThread
#006 {
#007 public:
#008
#009 CThread(void)
#010 {
#011 m_hThread = NULL;
#012 m_hEventExit = NULL;
#013 }
#014
#015 virtual ~CThread(void)
#016 {
#017 if (m_hThread)
#018 {
#019 //刪除的線程資源。
#020 ::CloseHandle(m_hThread);
#021 }
#022
#023 if (m_hEventExit)
#024 {
#025 //刪除事件。
#026 ::CloseHandle(m_hEventExit);
#027 }
#028
#029 }
#030
#031 //創(chuàng)建線程
#032 HANDLE CreateThread(void)
#033 {
#034 //創(chuàng)建退出事件。
#035 m_hEventExit = ::CreateEvent(NULL,TRUE,FALSE,NULL);
#036 if (!m_hEventExit)
#037 {
#038 //創(chuàng)建事件失敗。
#039 return NULL;
#040 }
#041
#042 //創(chuàng)建線程。
#043 m_hThread = ::CreateThread(
#044 NULL, //安全屬性使用缺省。
#045 0, //線程的堆棧大小。
#046 ThreadProc, //線程運行函數(shù)地址。
#047 this, //傳給線程函數(shù)的參數(shù)。
#048 0, //創(chuàng)建標志。
#049 &m_dwThreadID); //成功創(chuàng)建后的線程標識碼。
#050
#051 return m_hThread;
#052 }
#053
#054 //等待線程結(jié)束。
#055 void WaitFor(DWORD dwMilliseconds = INFINITE)
#056 {
#057 //發(fā)送退出線程信號。
#058 ::SetEvent(m_hEventExit);
#059
#060 //等待線程結(jié)束。
#061 ::WaitForSingleObject(m_hThread,dwMilliseconds);
#062 }
#063
#064 protected:
#065 //
#066 //線程運行函數(shù)。
#067 //蔡軍生 2007/09/21
#068 //
#069 static DWORD WINAPI ThreadProc(LPVOID lpParameter)
#070 {
#071 //轉(zhuǎn)換傳送入來的參數(shù)。
#072 CThread* pThread = reinterpret_cast<CThread *>(lpParameter);
#073 if (pThread)
#074 {
#075 //線程返回碼。
#076 //調(diào)用類的線程處理函數(shù)。
#077 return pThread->Run();
#078 }
#079
#080 //
#081 return -1;
#082 }
#083
#084 //線程運行函數(shù)。
#085 //在這里可以使用類里的成員,也可以讓派生類實現(xiàn)更強大的功能。
#086 //蔡軍生 2007/09/25
#087 virtual DWORD Run(void)
#088 {
#089 //輸出到調(diào)試窗口。
#090 ::OutputDebugString(_T("Run()線程函數(shù)運行/r/n"));
#091
#092 //線程循環(huán)。
#093 for (;;)
#094 {
#095 DWORD dwRet = WaitForSingleObject(m_hEventExit,0);
#096 if (dwRet == WAIT_TIMEOUT)
#097 {
#098 //可以繼續(xù)運行。
#099 TCHAR chTemp[128];
#100 wsprintf(chTemp,_T("ThreadID=%d/r/n"),m_dwThreadID);
#101 ::OutputDebugString(chTemp);
#102
#103 //目前沒有做什么事情,就讓線程釋放一下CPU。
#104 Sleep(10);
#105 }
#106 else if (dwRet == WAIT_OBJECT_0)
#107 {
#108 //退出線程。
#109 ::OutputDebugString(_T("Run() 退出線程/r/n"));
#110 break;
#111 }
#112 else if (dwRet == WAIT_ABANDONED)
#113 {
#114 //出錯。
#115 ::OutputDebugString(_T("Run() 線程出錯/r/n"));
#116 return -1;
#117 }
#118 }
#119
#120 return 0;
#121 }
#122
#123 protected:
#124 HANDLE m_hThread; //線程句柄。
#125 DWORD m_dwThreadID; //線程ID。
#126
#127 HANDLE m_hEventExit; //線程退出事件。
#128 };
#129
上面在第35行創(chuàng)建線程退出事件,第95行檢查事件是否可退出線程運行,第58行設置退出線程的事件。
發(fā)表于 @ 2007年09月25日 21:32:00|評論(0)|編輯 新一篇: Windows API一日一練(46)EnterCriticalSection和LeaveCriticalSection函數(shù) | 舊一篇: Windows API一日一練(44)wsprintf函數(shù)Win32 API 常用函數(shù)之二收藏新一篇: Win32 API 常用函數(shù)之三——注冊表操作(上) | 舊一篇: Win32 API 常用函數(shù)之一【事件】事件用處多是控制線程間的同步。 最典型的應用就是CreateThread之后等待線程函數(shù)的啟動。如Main線程里CreateThread,它之后的操作依賴于子線程,那么它一般會 在CreateThread之后判斷HANDLE是否有效,然后進入等待。(當然在這之前,一個Event是已經(jīng)創(chuàng)建好的,并初始化為未通知狀態(tài))子線程 啟動后完成了初始化操作,并設置Event為已通知狀態(tài)。這時,一直在等待該事件的Main線程發(fā)現(xiàn)該事件已經(jīng)得到通知,因此它就變成可調(diào)度線程。這時 Main線程知道子線程已經(jīng)完成了初始化操作。 CreateEvent函數(shù)用于創(chuàng)建一個Event,其原型如下: HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPTSTR lpName );
應用程序能夠確定它是否確實創(chuàng)建了一個新內(nèi)核對象,而不是打開了一個現(xiàn)有的對象。方法是在調(diào)用C r e a t e *函數(shù)后立即調(diào)用G e t L a s t E r r o r:如果為ERROR_ALREADY_EXISTS,那么表示系統(tǒng)內(nèi)已經(jīng)存在了這樣名字的對象。 Open*是去查看名字空間中是否有這個名字的內(nèi)核對象存在調(diào)用C r e a t e *函數(shù)與調(diào)用O p e n *函數(shù)之間的主要差別是,如果對象并不存在,那么C r e a t e *函數(shù)將創(chuàng)建該對象,而O p e n *函數(shù)則運行失敗。 PulseEvent函數(shù)使得事件變?yōu)橐淹ㄖ獱顟B(tài),然后立即又變?yōu)槲赐ㄖ獱顟B(tài),這就像在調(diào)用SetEvent后又立即調(diào)用ResetEvent函數(shù)一樣。 如果在人工重置的事件上調(diào)用PulseEvent函數(shù),那么在發(fā)出該事件時,等待該事件的任何一個線程或所有線程將變?yōu)榭烧{(diào)度線程。如果在自動重置事件上 調(diào)用P u l s e E v e n t函數(shù),那么只有一個等待該事件的線程變?yōu)榭烧{(diào)度線程。如果在發(fā)出事件時沒有任何線程在等待該事件,那么將不起任何作用。 【等待函數(shù)】 等待函數(shù)用來監(jiān)聽事件的已通知狀態(tài)。WaitForSingleObject和WaitForMultipleObjects兩個函數(shù)分別用以等待單個事件和多個事件。 DWORD WaitForSingleObject(
HANDLE hHandle, DWORD dwMilliseconds ); DWORD WaitForMultipleObjects( DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds ); dwMilliseconds 參數(shù)表明等待的時間,如果在這個時間段中事件為已通知狀態(tài),那么對于Single版本將返回WAIT_OBJECT_0,對于Multiple版本將返回 WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount– 1)。如果沒有等到將返回WAIT_TIMEOUT。 Multiple版本中的bWaitAll表示想要讓它使用何種方式等待。如果為該參數(shù)傳遞TRUE,那么在所有對象變?yōu)橐淹ㄖ獱顟B(tài)之前,該函數(shù)將不允許調(diào)用線程運行。一般是FALSE,即只要有一個事件被相應,則線程可調(diào)度。 發(fā)表于 @ 2007年10月28日 18:04:00|評論(0)|編輯 新一篇: Win32 API 常用函數(shù)之三——注冊表操作(上) | 舊一篇: Win32 API 常用函數(shù)之一 |
|
來自: oskycar > 《c\vc\opencv》