先舉一個有bug的例子:ios
#include <iostream> #include <windows.h> #include <process.h> using namespace std; #define MAX_SIZE 0x500 HANDLE g_hSubmit; HANDLE g_hReturn; HANDLE g_hStop; char g_szInput[MAX_SIZE] = {0}; unsigned int _stdcall ThreadServer(void* pParam) { while (TRUE) { int nWaitRes = WaitForSingleObject(g_hStop, 100); if (WAIT_OBJECT_0 == nWaitRes) break; WaitForSingleObject(g_hSubmit, INFINITE); printf("Recieve:%s\n", g_szInput); SetEvent(g_hReturn); } SetEvent(g_hStop); printf("Set stop\n"); return 0; } void main() { int count = 0; g_hSubmit = CreateEvent(NULL, FALSE, FALSE, NULL); g_hReturn = CreateEvent(NULL, FALSE, FALSE, NULL); g_hStop = CreateEvent(NULL, FALSE, FALSE, NULL); HANDLE hTheadServer = (HANDLE)_beginthreadex(NULL, 0, ThreadServer, NULL, 0, NULL); while (TRUE) { count++; printf("Input:"); cin.getline(g_szInput, MAX_SIZE); SetEvent(g_hSubmit); WaitForSingleObject(g_hReturn, INFINITE); if (count == 2){ Sleep(2000); SetEvent(g_hStop); break; } } HANDLE hHandle[3]; hHandle[0] = g_hStop; hHandle[1] = hTheadServer; WaitForMultipleObjects(2, hHandle, TRUE, INFINITE); CloseHandle(hTheadServer); CloseHandle(g_hReturn); CloseHandle(g_hStop); CloseHandle(g_hSubmit); getchar(); }
起初,我想要設置一個事件——g_hStop來通知線程,使得ThreadServer線程可以被主線程中止,可是這裏出現了一個問題,若是我刻意讓主線程Sleep2秒再去SetEvent,那麼等待g_hStop的wait函數就會超時,從而往下繼續執行等待Input,而此時主線程已經退出input循環,那麼就會死鎖。因此我改成使用全局變量來使得Threadserver線程退出:windows
#include <iostream> #include <windows.h> #include <process.h> using namespace std; #define MAX_SIZE 0x500 HANDLE g_hSubmit; HANDLE g_hReturn; HANDLE g_hStop; int g_nCount = 0; char g_szInput[MAX_SIZE] = {0}; unsigned int _stdcall ThreadServer(void* pParam) { while (TRUE) { if (g_nCount == 2) break; WaitForSingleObject(g_hSubmit, INFINITE); printf("Recieve:%s\n", g_szInput); SetEvent(g_hReturn); } SetEvent(g_hStop); printf("Set stop\n"); return 0; } void main() { g_hSubmit = CreateEvent(NULL, FALSE, FALSE, NULL); g_hReturn = CreateEvent(NULL, FALSE, FALSE, NULL); g_hStop = CreateEvent(NULL, FALSE, FALSE, NULL); HANDLE hTheadServer = (HANDLE)_beginthreadex(NULL, 0, ThreadServer, NULL, 0, NULL); while (TRUE) { g_nCount++; printf("Input:"); cin.getline(g_szInput, MAX_SIZE); SetEvent(g_hSubmit); WaitForSingleObject(g_hReturn, INFINITE); if (g_nCount == 2){ Sleep(2000); SetEvent(g_hStop); break; } } HANDLE hHandle[2]; hHandle[0] = g_hStop; hHandle[1] = hTheadServer; WaitForMultipleObjects(2, hHandle, TRUE, INFINITE); CloseHandle(hTheadServer); CloseHandle(g_hReturn); CloseHandle(g_hSubmit); getchar(); }
三種方式改進:函數
一、若是你非要使用第一種狀況,那麼請把等待時間設置的長一些,不要是100毫秒,起碼要是等待十秒,確保事件觸發後,不會超時。spa
二、在代碼設計的時候,就不要在while中使用兩個waitforsingleobject,這種設計就給死鎖帶來了可能性:線程
三、使用waitformultiobject等待兩個event之一,而後判斷等到的是哪一個,從而決定來作什麼設計
一個Mutex和semaphore合用的例子:code
#include <iostream> #include <windows.h> #include <vector> #include <process.h> using namespace std; #define MAX_SIZE 10 long g_ServerCount = 0; class CQueue{ public: CQueue(); ~CQueue(); void Append(); void Remove(); private: vector<int> m_vecQueue; HANDLE m_hMutex; HANDLE m_hSem; HANDLE m_hHandles[2]; }; CQueue g_c; CQueue::CQueue() { m_hMutex = CreateMutex(NULL, FALSE, NULL); m_hSem = CreateSemaphore(NULL, 0, 10, NULL); m_hHandles[0] = m_hMutex; m_hHandles[1] = m_hSem; } CQueue::~CQueue() { CloseHandle(m_hMutex); CloseHandle(m_hSem); } void CQueue::Append(){ DWORD dwRet = WaitForSingleObject(m_hMutex, INFINITE); InterlockedExchangeAdd(&g_ServerCount, 1); if (dwRet == WAIT_OBJECT_0) { LONG lPrevCount; int bRet = ReleaseSemaphore(m_hSem, 1, &lPrevCount); if (bRet) { m_vecQueue.push_back(g_ServerCount); printf("Add element %d\n", g_ServerCount); } } ReleaseMutex(m_hMutex); } void CQueue::Remove() { DWORD dwRet = WaitForMultipleObjects(2, m_hHandles, TRUE, INFINITE); if (WAIT_OBJECT_0 == dwRet) { printf("Remove element %d\n", m_vecQueue.back()); m_vecQueue.pop_back(); } ReleaseMutex(m_hMutex); } unsigned int _stdcall ServerThread(void* pParam) { while (TRUE) { Sleep(20); g_c.Append(); } return 0; } unsigned int _stdcall ClientThread(void* pParam) { while (TRUE) { Sleep(20); g_c.Remove(); } return 0; } void main() { HANDLE h_Handles[3]; h_Handles[0] = (HANDLE)_beginthreadex(NULL, 0, ServerThread, NULL, 0, NULL); h_Handles[1] = (HANDLE)_beginthreadex(NULL, 0, ServerThread, NULL, 0, NULL); h_Handles[2] = (HANDLE)_beginthreadex(NULL, 0, ClientThread, NULL, 0, NULL); WaitForMultipleObjects(_countof(h_Handles), h_Handles, TRUE, INFINITE); for (int i = 0; i < _countof(h_Handles); i++) CloseHandle(h_Handles[i]); getchar(); }