討論

一兩種方式建立,一種爲自動重置,在其餘線程使用WaitForSingleObject等待到事件對象變爲有信號後該事件對象自動又變爲無信號狀態,一種爲人工重置在其餘線程使用WaitForSingleObject等待到事件對象變爲有信號後該事件對象狀態不變。例若有多個線程都在等待一個線程運行結束,咱們就可使用人工重置事件,在被等待的線程結束時設置該事件爲有信號狀態,這樣其餘的多個線程對該事件的等待都會成功(由於該事件的狀態不會被自動重置)。事件相關的API以下: 

建立事件對象:
HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes,// 安全屬性,NULL表示使用默認的安全描述
  BOOL bManualReset,  // 是否爲人工重置
  BOOL bInitialState, // 初始狀態是否爲有信號狀態
  LPCTSTR lpName      // 名字
);
打開事件對象:
HANDLE OpenEvent(
  DWORD dwDesiredAccess,  // 存取方式
  BOOL bInheritHandle,    // 是否可以被繼承
  LPCTSTR lpName          // 名字
);
設置事件爲無信號狀態:
BOOL ResetEvent(
  HANDLE hEvent   // 句柄
);
設置事件有無信號狀態:
BOOL SetEvent(
  HANDLE hEvent   // 句柄
);
關閉事件對象:
BOOL CloseHandle(
  HANDLE hObject   // 句柄
);

下面的代碼演示了自動重置和人工重置事件在使用中的不一樣效果: 

DWORD threadA(void* pD)
{
int iID=(int)pD;
//在內部從新打開
HANDLE hCounterIn=OpenEvent(EVENT_ALL_ACCESS,FALSE,"sam sp 44");

printf("\tthread %d begin\n",iID);
//設置成爲有信號狀態
Sleep(1000);
SetEvent(hCounterIn);
Sleep(1000);
printf("\tthread %d end\n",iID);
CloseHandle(hCounterIn);
return 0;
}

DWORD threadB(void* pD)
{//等待threadA結束後在繼續執行
int iID=(int)pD;
//在內部從新打開
HANDLE hCounterIn=OpenEvent(EVENT_ALL_ACCESS,FALSE,"sam sp 44");

if(WAIT_TIMEOUT == WaitForSingleObject(hCounterIn,10*1000))
{
printf("\t\tthread %d wait time out\n",iID);
}
else
{
printf("\t\tthread %d wait ok\n",iID);
}
CloseHandle(hCounterIn);
return 0;
}

//in main function
{
HANDLE hCounter=NULL;
if( (hCounter=OpenEvent(EVENT_ALL_ACCESS,FALSE,"sam sp 44"))==NULL)
{
//若是沒有其餘進程建立這個事件,則從新建立,該事件爲人工重置事件
hCounter = CreateEvent(NULL,TRUE,FALSE,"sam sp 44");
}

//建立線程
HANDLE hThread[3];
printf("test of manual rest event\n");
CWinThread* pT1=AfxBeginThread((AFX_THREADPROC)threadA,(void*)1);
CWinThread* pT2=AfxBeginThread((AFX_THREADPROC)threadB,(void*)2);
CWinThread* pT3=AfxBeginThread((AFX_THREADPROC)threadB,(void*)3);
hThread[0]=pT1->m_hThread;
hThread[1]=pT2->m_hThread;
hThread[2]=pT3->m_hThread;
//等待線程結束
WaitForMultipleObjects(3,hThread,TRUE,INFINITE);
//關閉句柄
CloseHandle(hCounter);

if( (hCounter=OpenEvent(EVENT_ALL_ACCESS,FALSE,"sam sp 44"))==NULL)
{
//若是沒有其餘進程建立這個事件,則從新建立,該事件爲自動重置事件
hCounter = CreateEvent(NULL,FALSE,FALSE,"sam sp 44");
}
//建立線程
printf("test of auto rest event\n");
pT1=AfxBeginThread((AFX_THREADPROC)threadA,(void*)1);
pT2=AfxBeginThread((AFX_THREADPROC)threadB,(void*)2);
pT3=AfxBeginThread((AFX_THREADPROC)threadB,(void*)3);
hThread[0]=pT1->m_hThread;
hThread[1]=pT2->m_hThread;
hThread[2]=pT3->m_hThread;
//等待線程結束
WaitForMultipleObjects(3,hThread,TRUE,INFINITE);
//關閉句柄
CloseHandle(hCounter);
}

從執行結果中咱們能夠看到在第二次執行時因爲使用了自動重置事件threadB中只有一個線程可以等待到threadA中釋放的事件對象。 

在處理多進程/線程的同步問題時必需要當心避免發生死鎖問題,好比說如今有兩個互斥量A和B,兩個線程tA和tB,他們在執行前都須要獲得這兩個互斥量,但如今這種狀況發生了,tA擁有了互斥量A,tB擁有了互斥量B,但它們同時都在等待擁有另外一個互斥量,這時候顯然誰也不可能獲得本身但願的資源。這種互相擁有對方所擁有的資源並且都在等待對方擁有的資源的狀況就稱爲死鎖。關於這個問題更詳細的介紹請參考其餘參考書。 

在MFC中對於各類同步對象都提供了相對應的類

在這些類中封裝了上面介紹的對象建立,打開,控制,刪除功能。可是若是要使用等待功能則須要使用另外兩個類:CSingleLock和CMultiLock。這兩個類中封裝了WaitForSingleObject和WaitForMultipleObjects函數。若是你們覺的須要能夠看看這些類的定義,我想經過上面的介紹能夠很容易理解,可是在對象同步問題上我以爲使用API函數比使用MFC類更爲直觀和方便。安全

相關文章
相關標籤/搜索