VC 中線程同步技術分析4

2021-04-13 08:17:09 字數 3431 閱讀 3677

管理事件核心物件

在前面講述執行緒通訊時曾使用過事件核心物件來進行執行緒間的通訊,除此之外,事件核心物件也可以通過通知操作的方式來保持執行緒的同步。對於前面那段使用臨界區保持執行緒同步的**可用事件物件的執行緒同步方法改寫如下:

// 事件控制代碼

handle hevent = null;

// 共享資源

char g_carray[10];

……uint threadproc12(lpvoid pparam)

// 處理完成後即將事件物件置位

setevent(hevent);

return 0;

}uint threadproc13(lpvoid pparam)

// 處理完成後即將事件物件置位

setevent(hevent);

return 0;}……

void csample08view::onevent()

在建立執行緒前,首先建立乙個可以自動復位的事件核心物件hevent,而執行緒函式則通過waitforsingleobject()等待函式無限等待hevent的置位,只有在事件置位時waitforsingleobject()才會返回,被保護的**將得以執行。對於以自動復位方式建立的事件物件,在其置位後一被waitforsingleobject()等待到就會立即復位,也就是說在執行threadproc12()中的受保護**時,事件物件已經是復位狀態的,這時即使有threadproc13()對cpu的搶占,也會由於waitforsingleobject()沒有hevent的置位而不能繼續執行,也就沒有可能破壞受保護的共享資源。在threadproc12()中的處理完成後可以通過setevent()對hevent的置位而允許threadproc13()對共享資源g_carray的處理。這裡setevent()所起的作用可以看作是對某項特定任務完成的通知。

使用臨界區只能同步同一程序中的執行緒,而使用事件核心物件則可以對程序外的執行緒進行同步,其前提是得到對此事件物件的訪問權。可以通過openevent()函式獲取得到,其函式原型為:

handle openevent(

dword dwdesiredaccess, // 訪問標誌

bool binherithandle, // 繼承標誌

lpctstr lpname // 指向事件物件名的指標

);如果事件物件已建立(在建立事件時需要指定事件名),函式將返回指定事件的控制代碼。對於那些在建立事件時沒有指定事件名的事件核心物件,可以通過使用核心物件的繼承性或是呼叫duplicatehandle()函式來呼叫createevent()以獲得對指定事件物件的訪問權。在獲取到訪問權後所進行的同步操作與在同乙個程序中所進行的執行緒同步操作是一樣的。

如果需要在乙個執行緒中等待多個事件,則用waitformultipleobjects()來等待。waitformultipleobjects()與waitforsingleobject()類似,同時監視位於控制代碼陣列中的所有控制代碼。這些被監視物件的控制代碼享有平等的優先權,任何乙個控制代碼都不可能比其他控制代碼具有更高的優先權。waitformultipleobjects()的函式原型為:

dword waitformultipleobjects(

dword ncount, // 等待控制代碼數

const handle *lphandles, // 控制代碼陣列首位址

bool fwaitall, // 等待標誌

dword dwmilliseconds // 等待時間間隔

);引數ncount指定了要等待的核心物件的數目,存放這些核心物件的陣列由lphandles來指向。fwaitall對指定的這ncount個核心物件的兩種等待方式進行了指定,為true時當所有物件都被通知時函式才會返回,為false則只要其中任何乙個得到通知就可以返回。dwmilliseconds在這裡的作用與在waitforsingleobject()中的作用是完全一致的。如果等待超時,函式將返回wait_timeout。如果返回wait_object_0到wait_object_0+ncount-1中的某個值,則說明所有指定物件的狀態均為已通知狀態(當fwaitall為true時)或是用以減去wait_object_0而得到發生通知的物件的索引(當fwaitall為false時)。如果返回值在wait_abandoned_0與wait_abandoned_0+ncount-1之間,則表示所有指定物件的狀態均為已通知,且其中至少有乙個物件是被丟棄的互斥物件(當fwaitall為true時),或是用以減去wait_object_0表示乙個等待正常結束的互斥物件的索引(當fwaitall為false時)。 下面給出的**主要展示了對waitformultipleobjects()函式的使用。通過對兩個事件核心物件的等待來控制線程任務的執行與中途退出:

// 存放事件控制代碼的陣列

handle hevents[2];

uint threadproc14(lpvoid pparam)

}afxmessagebox("執行緒退出!");

return 0;}……

void csample08view::onstartevent()

void csample08view::onendevent()

mfc為事件相關處理也提供了乙個cevent類,共包含有除建構函式外的4個成員函式pulseevent()、resetevent()、setevent()和unlock()。在功能上分別相當與win32 api的pulseevent()、resetevent()、setevent()和closehandle()等函式。而建構函式則履行了原createevent()函式建立事件物件的職責,其函式原型為:

cevent(bool binitiallyown = false, bool bmanualreset = false, lpctstr lpszname = null, lpsecurity_attributes lpsaattribute = null );

按照此預設設定將建立乙個自動復位、初始狀態為復位狀態的沒有名字的事件物件。封裝後的cevent類使用起來更加方便,圖2即展示了cevent類對a、b兩線程的同步過程:

圖2 cevent類對執行緒的同步過程示意

b執行緒在執行到cevent類成員函式lock()時將會發生阻塞,而a執行緒此時則可以在沒有b執行緒干擾的情況下對共享資源進行處理,並在處理完成後通過成員函式setevent()向b發出事件,使其被釋放,得以對a先前已處理完畢的共享資源進行操作。可見,使用cevent類對執行緒的同步方法與通過api函式進行執行緒同步的處理方法是基本一致的。前面的api處理**可用cevent類將其改寫為:

// mfc事件類物件

cevent g_clsevent;

uint threadproc22(lpvoid pparam)

// 事件置位

g_clsevent.setevent();

return 0;

}uint threadproc23(lpvoid pparam)

return 0;}……

void csample08view::oneventmfc()

VC 中線程同步技術分析4

管理事件核心物件 在前面講述執行緒通訊時曾使用過事件核心物件來進行執行緒間的通訊,除此之外,事件核心物件也可以通過通知操作的方式來保持執行緒的同步。對於前面那段使用臨界區保持執行緒同步的 可用事件物件的執行緒同步方法改寫如下 事件控制代碼 handle hevent null 共享資源 char g...

VC 中線程同步技術分析3

管理事件核心物件 在前面講述執行緒通訊時曾使用過事件核心物件來進行執行緒間的通訊,除此之外,事件核心物件也可以通過通知操作的方式來保持執行緒的同步。對於前面那段使用臨界區保持執行緒同步的 可用事件物件的執行緒同步方法改寫如下 事件控制代碼 handle hevent null 共享資源 char g...

VC 中線程同步技術分析5

管理事件核心物件 在前面講述執行緒通訊時曾使用過事件核心物件來進行執行緒間的通訊,除此之外,事件核心物件也可以通過通知操作的方式來保持執行緒的同步。對於前面那段使用臨界區保持執行緒同步的 可用事件物件的執行緒同步方法改寫如下 事件控制代碼 handle hevent null 共享資源 char g...