事件(Event)同步對(duì)象
創(chuàng)新互聯(lián)建站主要從事成都網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)伊寧,10余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專(zhuān)業(yè),歡迎來(lái)電咨詢建站服務(wù):18980820575
(內(nèi)核級(jí)別)事件內(nèi)核對(duì)象包含:
1 一個(gè)使用計(jì)數(shù)器
2 一個(gè)表示事件是否是自動(dòng)重置還是手動(dòng)重置的布爾值
3 一個(gè)表示事件有沒(méi)有被觸發(fā)的布爾值
4 當(dāng)觸發(fā)為true時(shí),等待該事件的線程變?yōu)榭烧{(diào)度狀態(tài)
5 事件的觸發(fā)表示一個(gè)操作已經(jīng)完成
作用: 通知其他線程,我已經(jīng)完成讀寫(xiě)操作了,輪到你們來(lái)做了。
他分為兩種類(lèi)型:
1是手動(dòng)重置事件,也就是要進(jìn)行手動(dòng)的觸發(fā)和非觸發(fā)狀態(tài)的切換.
2是自動(dòng)重置事件,這種情況下只需要設(shè)置觸發(fā)事件,不用管什么時(shí)候切換觸發(fā)狀態(tài)。
盡量使用手動(dòng)重置方式, 因?yàn)檫@種方式可控性強(qiáng),不易出錯(cuò).自動(dòng)重置事件會(huì)引起成功等待的一些副作用.
相關(guān)的api:
1 CreateEvent函數(shù)
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,//安全屬性
BOOL bManualReset, //復(fù)位方式
BOOL bInitialState,//初始狀態(tài)
LPCTSTR lpName //對(duì)象名稱(chēng));
返回一個(gè)Handle,事件同步對(duì)象的句柄。
參數(shù)1 lpEventAttributes 權(quán)限,一般NULL就是默認(rèn)權(quán)限
參數(shù)2 bManualReset TRUE代表手動(dòng)重置,FALSE自動(dòng)重置
參數(shù)3 bInitialState TRUE代表可觸發(fā), FALSE非觸發(fā)(阻塞)
參數(shù)3 lpName 一個(gè)對(duì)象的名稱(chēng),跨進(jìn)程尋址,一般NULL
2 SetEvent函數(shù),設(shè)置事件對(duì)象為有信號(hào)狀態(tài)
BOOL SetEvent( HANDLE hEvent);
hEvent 設(shè)置事件對(duì)象的句柄 就是CreateEvent返回的句柄.
當(dāng)調(diào)用這個(gè)函數(shù)后,這個(gè)事件就是觸發(fā)的狀態(tài)。
3 ResetEvent 函數(shù),設(shè)置事件對(duì)象為無(wú)信號(hào),非觸發(fā)
BOOL ResetEvent(HANDLE hEvent);
hEvent 設(shè)置事件對(duì)象的句柄 就是CreateEvent返回的句柄.
當(dāng)調(diào)用這個(gè)函數(shù)后,這個(gè)事件就是非觸發(fā)的狀態(tài)。
使用例子
還是用之前的代碼,就是一個(gè)小球碰到邊界會(huì)反彈的程序.
我們需要三個(gè)線程,三個(gè)全局的事件對(duì)象句柄.
WndProc3中代碼如下:
case WM_CREATE: { //系統(tǒng)中基于對(duì)話框字體的高度 int cyChar = HIWORD(GetDialogBaseUnits()); thrParams3.hwnd = hWnd; thrParams3.cyChar = cyChar; //創(chuàng)建事件對(duì)象 g_hEvent1 = CreateEvent(NULL, TRUE,TRUE,NULL); //手動(dòng)復(fù)位 事件 有信號(hào) g_hEvent2 = CreateEvent(NULL, TRUE, FALSE, NULL);//手動(dòng)復(fù)位 事件 無(wú)信號(hào) g_hEvent3 = CreateEvent(NULL, TRUE, FALSE, NULL);//手動(dòng)復(fù)位 事件 無(wú)信號(hào) // 創(chuàng)建三個(gè)線程 HANDLE handleBall1 = CreateThread(NULL, 0, ThrBallProc1, &thrParams3, 0, NULL); HANDLE handleBall2 = CreateThread(NULL, 0, ThrBallProc2, &thrParams3, 0, NULL); HANDLE handleBall3 = CreateThread(NULL, 0, ThrBallProc3, &thrParams3, 0, NULL); //關(guān)閉線程句柄 CloseHandle(handleBall1); CloseHandle(handleBall2); CloseHandle(handleBall3); }
上面三個(gè)事件都是要手動(dòng)復(fù)位的。
來(lái)看線程函數(shù)
前面依然使用WaitForSingleObject來(lái)進(jìn)行等待,但是用的是事件的對(duì)象, 然后最好要手動(dòng)的設(shè)置事件的信號(hào)。
DWORD WINAPI ThrBallProc1(LPVOID lp) { PPARAMS param3 = static_cast<PPARAMS>(lp); //休眠1秒 Sleep(1000); //等待事件 使用INFINITE所以是無(wú)限等待 只有觸發(fā)才返回 WaitForSingleObject(g_hEvent1, INFINITE); //獲取dc HDC hdc = GetDC(param3->hwnd); //生成隨機(jī)數(shù)種子 srand(GetTickCount()); //創(chuàng)建筆和畫(huà)刷 HPEN white_pen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255)); HBRUSH green_brush = CreateSolidBrush(RGB(0,255,0)); //綠色的小球 HBRUSH white_brush = CreateSolidBrush(RGB(255, 255, 255)); //小球的開(kāi)始位置 int ball_x = param3->cxClient / 2; int ball_y = param3->cyClient / 2; //速度 int xv = -4 + rand() % 8; int yv = -4 + rand() % 8; DWORD dwCurTime = GetTickCount(); while (1) { //首先選擇白色筆和白色畫(huà)刷 設(shè)置上下文中去 SelectObject(hdc, white_pen); SelectObject(hdc, white_brush); // 繪制圓形小球 Ellipse(hdc, ball_x, ball_y, ball_x + 32, ball_y + 32); //移動(dòng)小球 ball_x += xv; ball_y += yv; //如果x軸 碰到邊界 那就往反方向走 if (ball_x <0 || ball_x > param3->cxClient - 32) { xv = -xv; ball_x += xv; } else // 或者是Y軸 { if (ball_y <17 || ball_y > param3->cyClient - 32) { yv = -yv; ball_y += yv; } } SelectObject(hdc, white_pen); SelectObject(hdc, green_brush); //畫(huà)小球 Ellipse(hdc, ball_x, ball_y, ball_x + 32, ball_y + 32); DWORD dwTime = GetTickCount() - dwCurTime; //當(dāng)前時(shí)間 和第一次運(yùn)行的時(shí)間差 Sleep(10); //判斷現(xiàn)在的時(shí)間 減去初始化時(shí)間(循環(huán)外的那個(gè)時(shí)間) 是不是大于10秒鐘 if ((GetTickCount() - dwCurTime) > 1000 * 10) { //完成了當(dāng)前線程操作 break; } } //線程的工作完成 //刪除GDI對(duì)象 DeleteObject(white_brush); DeleteObject(green_brush); DeleteObject(white_pen); ReleaseDC(param3->hwnd,hdc ); //設(shè)置窗口無(wú)效,并更新窗口 InvalidateRect(param3->hwnd,NULL,TRUE); UpdateWindow(param3->hwnd); // 手動(dòng)設(shè)置事件信號(hào) //讓1號(hào) 事件對(duì)象 無(wú)信號(hào) 讓2號(hào)事件 有信號(hào) ResetEvent(g_hEvent1); SetEvent(g_hEvent2); return 0; }
我們看到,三個(gè)線程都有一個(gè)繪制小球,但是他門(mén)沒(méi)有同步出現(xiàn),
而是第一個(gè)小球操作完10秒(或者是某個(gè)操作完成),他必須是有
一個(gè)對(duì)象,手動(dòng)的設(shè)置觸發(fā),那這個(gè)等待函數(shù)對(duì)應(yīng)的就會(huì)返回。
如果使用自動(dòng)重置事件呢?
//創(chuàng)建事件對(duì)象 g_hEvent1 = CreateEvent(NULL, FALSE,TRUE,NULL); //改成自動(dòng)復(fù)位 g_hEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL); g_hEvent3 = CreateEvent(NULL, FALSE, FALSE, NULL);
然后在這個(gè)等待函數(shù)當(dāng)作
WaitForSingleObject,當(dāng)?shù)却搅艘粋€(gè)Event事件,他是觸發(fā)狀態(tài),
他會(huì)判斷他是不是自動(dòng)重置事件的,如果是自動(dòng)重置事件的話,
他會(huì)立即調(diào)用ResetEvent將這個(gè)事件設(shè)置成,非觸發(fā)狀態(tài).
這種情況下, 最后可以不掉用這個(gè)函數(shù)。
因?yàn)樗诘却瘮?shù)中,以及調(diào)用了這個(gè)函數(shù).
然后將這個(gè)ResetEvent注釋掉,
這樣就變成自動(dòng)復(fù)位的了。
網(wǎng)頁(yè)題目:VC++線程同步(四)事件使用例子
當(dāng)前路徑:http://chinadenli.net/article12/pehhdc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動(dòng)態(tài)網(wǎng)站、網(wǎng)站策劃、建站公司、云服務(wù)器、外貿(mào)建站、軟件開(kāi)發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)