VC訊號量和執行緒的用法

ForTechnology發表於2011-08-14
Normal 0 7.8 磅 0 2 false false false MicrosoftInternetExplorer4 VC訊號量和執行緒的用法

20090904 下午 08:23

先舉個例:
CSemaphore semaphore(1,2);

UINT BoxA(LPVOID pParam)
{
WaitForSingleObject(semaphore.m_hObject,INFINITE);
/*
AfxMessageBox("BoxA");
*/
ReleaseSemaphore(semaphore.m_hObject,1,NULL);
return 0;
}
UINT BoxB(LPVOID pParam)
{
WaitForSingleObject(semaphore.m_hObject,INFINITE);
/*
AfxMessageBox("BoxB");
*/
ReleaseSemaphore(semaphore.m_hObject,1,NULL);
return 0;

}
UINT BoxC(LPVOID pParam)
{
WaitForSingleObject(semaphore.m_hObject,INFINITE);
/*
AfxMessageBox("BoxC");
*/
ReleaseSemaphore(semaphore.m_hObject,1,NULL);
return 0;

}

......

void CMyDlg::OnStart()
{
CWinThread *pWriteA=AfxBeginThread(BoxA, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
pWriteA->ResumeThread();

CWinThread *pWriteB=AfxBeginThread(BoxB, this,, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
pWriteB->ResumeThread();

CWinThread *pWriteC=AfxBeginThread(BoxC, this,, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
pWriteC->ResumeThread();
}
這段示例程式主要有三部分:訊號量的建立、執行緒定義、執行緒呼叫。CSemaphore semaphore(1,2)1為訊號量的初始值(即此時只允許1個執行緒能擁有此訊號量,當然這個值在0

最大值之間可以增加或減小),2為訊號量的最大值(也就是最大執行緒訪問數目),比如此處設為2,表示此訊號量最多隻允許倆個執行緒同時擁有它,其它執行緒想要獲得此訊號量的

話只能等待這兩個執行緒釋放此訊號量,或呼叫ReleaseSemaphore(semaphore.m_hObject,1,NULL)函式來增加訊號量的值。WaitForSingleObject(semaphore.m_hObject,INFINITE)

數呼叫後訊號量的值自動減1,當減到0時,其它執行緒就不能再利用此訊號量了。ReleaseSemaphore(semaphore.m_hObject,1,NULL)函式使訊號量的值加1,當加到最大值時,訊號量

的值不再增大,此函式成功時返回1,呼叫失敗時返回0,當訊號量計數器已達到最大值時再呼叫此函式就會呼叫失敗,或者此函式的第三個引數+此時訊號量的值>最大值時也會調

用失敗,呼叫失敗的意思是忽略此函式,程式繼續執行。

關於將類的成員函式作為執行緒:
以上提到的執行緒,都是通過標準UINT func(LPVOID pParam)形式來定義,但是有的時候成員函式需要等待訊號量或者成員函式的執行程式碼比較大時,不為其分配其它的執行緒的話程式的效率將會受到影響。將某 類的成員函式單獨作為一條執行緒來執行最常用的辦法是將成員函式申明為靜態,即static UINT func(LPVOID pParam)
其它的處理方法和普通執行緒差不多,但是靜態成員函式只能訪問類的靜態成員,想要訪問非靜態成員的話可以將this指標傳遞給pParam引數來實現,舉例如下:

檔案1
CSemaphore semaphore(0,1);
class CVideoNetDlg:public CDialog
{
public:
CViewDlg *viewdlg;
......
}

UINT CVideoNetDlg::Thread_OpenViewDlg(LPVOID param)
{
WaitForSingleObject(semaphore.m_hObject,300);//
訊號量減1
CVideoNetDlg *dlg = (CVideoNetDlg*)param;
dlg->viewdlg->DoModal();
return NULL;
}  

void CVideoNetDlg::OnView()
{
dcontrol.SendViewApply();
CWinThread *pWriteC=AfxBeginThread(Thread_OpenViewDlg, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
pWriteC->ResumeThread();
}

檔案2
case MESG_VIEW:
{
memcpy(CViewDlg::clientdata,&data[1],length-1);
ReleaseSemaphore(semaphore.m_hObject,1,NULL);
}

此段程式的目的是在處理函式OnView()時,獲得訊號量semaphore後再呼叫CviewDlg類的模式對話方塊(其實是這樣的,點選某個菜 單彈出對話方塊,但是這個對話方塊初始化時必須要利用陣列CViewDlg::clientdata的資料,而這個陣列是在點選這個選單時傳送某程式碼到遠端 機,再從遠端機返回的資料得到賦值的。)
實現方法就是建立一個二值訊號量,並置其初始值為0,這樣在點選選單時執行緒由於得不到訊號量一直處於等待狀態,模式對話方塊就不會被呼叫,直到檔案2中的數 組得到賦值後,訊號量釋放(即增1)這個執行緒獲得了訊號量就繼續往下執行,呼叫對話方塊。這樣一來,就保證了對話方塊使用陣列 CViewDlg::clientdata來初始化。

另外,此執行緒Thread_OpenViewDlg(LPVOID param)為類CVideoNetDlg的靜態成員函式,但是很顯然它使用了類CVideoNetDlg的非靜態公有成員viewdlg,這就是利用 this指標在***.OnView()函式中將CVideoNetDlg的物件***傳遞給了param引數,在通過 (CVideoNetDlg*)paramLPVOID型別轉換為CVideoNetDlg,執行CVideoNetDlg *dlgdlg已經成了CVideoNetDlg的物件並獲得了***的指標,這樣就可以呼叫其成員viewdlg了。

最後,為什麼將訊號量和執行緒放在一起來分析,其實訊號量就是執行緒程式設計,自己一個訊號量也是很簡單的事情:分配一個額外的執行緒,在這個執行緒中用 while迴圈來檢測你自定義的訊號量的變化,由於while在單獨的執行緒中執行,它不會影響主執行緒執行的。vc專門用這種機制只不過是來簡化程式設計罷了 (個人愚見...)。

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25897606/viewspace-704805/,如需轉載,請註明出處,否則將追究法律責任。

相關文章