1. 互斥量,Mutex
- #include <Windows.h>
- #include <iostream>
- using namespace std;
- DWORD WINAPI Thread1(LPVOID lpParmeter);
- DWORD WINAPI Thread2(LPVOID lpParmeter);
- static HANDLE g_hMutex = INVALID_HANDLE_VALUE;
- static int g_iCnt = 100;
- int main()
- {
- HANDLE hThread1 = INVALID_HANDLE_VALUE;
- HANDLE hThread2 = INVALID_HANDLE_VALUE;
- g_hMutex = CreateMutex(NULL, FALSE, "Mutex");
- // 第二個參數:創建者是否擁有所有權,FALSE為沒有所有權,
- // 遇到第一個WaitForSingleObject的時候就把所有權給它,
- // 所以Thread1里面的WaitForSingleObject(g_hMutex, INFINITE)能夠繼續執行
- if (!g_hMutex)
- {
- cout << "Failed to CreateMutex !" << endl;
- return 0;
- }
- hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
- hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
- Sleep(4000); // 讓2個線程有足夠的時間執行完操作。
- CloseHandle(hThread1);
- CloseHandle(hThread2);
- system("PAUSE");
- return 0;
- }
- DWORD WINAPI Thread1(LPVOID lpParmeter)
- {
- while (true)
- {
- // 請求事件對象
- WaitForSingleObject(g_hMutex, INFINITE); // INFINITE: 長時間等待,差不多50天左右吧!
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "Thread1:" << g_iCnt-- << endl;
- ReleaseMutex(g_hMutex); // 釋放資源
- }
- else
- {
- ReleaseMutex(g_hMutex);
- break;
- }
- }
- return 0;
- }
- DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
- {
- while (true)
- {
- // 請求事件對象
- WaitForSingleObject(g_hMutex,INFINITE);
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "thread2:" << g_iCnt-- << endl;
- ReleaseMutex(g_hMutex);
- }
- else
- {
- ReleaseMutex(g_hMutex);
- break;
- }
- }
- return 0;
- }
幾個注意的地方:
(1)互斥量為內核對象,能夠與其他線程或特殊事件取得同步;
(2)速度比臨界區要慢;
(3)互斥量對象與所有其它內核對象的不同之處在於它是被線程所擁有的,互斥量對象除了記錄當前信號狀態外,還要記住此時那個線程擁有它。
(4)這個常來被運用於限制程序啟動次數!
2.事件 Event
- #include <Windows.h>
- #include <iostream>
- using namespace std;
- DWORD WINAPI Thread1(LPVOID lpParmeter);
- DWORD WINAPI Thread2(LPVOID lpParmeter);
- static HANDLE g_hEvent = INVALID_HANDLE_VALUE;
- static int g_iCnt = 100;
- int main()
- {
- HANDLE hThread1 = INVALID_HANDLE_VALUE;
- HANDLE hThread2 = INVALID_HANDLE_VALUE;
- g_hEvent = CreateEvent(NULL, false, false, "Event");
- if (!g_hEvent)
- {
- cout << "Failed to CreateEvent !" << endl;
- return 0;
- }
- /*HANDLE CreateEvent(
- LPSECURITY_ATTRIBUTES lpEventAttributes, // SECURITY_ATTRIBUTES結構指針,可為NULL
- BOOL bManualReset, // 手動/自動
- // TRUE: 在WaitForSingleObject后必須手動調用ResetEvent清除信號
- // FALSE:在WaitForSingleObject后,系統自動清除事件信號
- BOOL bInitialState, // 初始狀態
- LPCTSTR lpName // 事件的名稱
- );*/
- hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
- hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
- SetEvent(g_hEvent);
- Sleep(4000); // 讓2個線程有足夠的時間執行完操作。
- CloseHandle(hThread1);
- CloseHandle(hThread2);
- system("PAUSE");
- return 0;
- }
- DWORD WINAPI Thread1(LPVOID lpParmeter)
- {
- while (true)
- {
- // 請求事件對象
- WaitForSingleObject(g_hEvent, INFINITE); // INFINITE: 長時間等待,差不多50天左右吧!
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "Thread1:" << g_iCnt-- << endl;
- SetEvent(g_hEvent);
- }
- else
- {
- SetEvent(g_hEvent);
- break;
- }
- }
- return 0;
- }
- DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
- {
- while (true)
- {
- // 請求事件對象
- WaitForSingleObject(g_hEvent,INFINITE);
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "thread2:" << g_iCnt-- << endl;
- SetEvent(g_hEvent);
- }
- else
- {
- SetEvent(g_hEvent);
- break;
- }
- }
- return 0;
- }
幾個注意的地方:
(1).和Mutex使用差不多,只有細微的差別;
(2).可以使用SetEvent或ResetEvent改變其狀態;
(3).在應用程序中任意一處沒有正確的按照規則調用SetEvent或ResetEvent,將達不到同步或互斥的目的;
(4).一般來說,都是利用Event來進行同步,而不是我們這里的讓它來達到互斥;
(5).Event處於無信號狀態時,相關線程或進程退出,系統並不會嘗試將其置為有信號狀態;
3.臨界區 CRITICAL_SECTION
- #include <Windows.h>
- #include <iostream>
- using namespace std;
- DWORD WINAPI Thread1(LPVOID lpParmeter);
- DWORD WINAPI Thread2(LPVOID lpParmeter);
- CRITICAL_SECTION g_CriticalSection; // 定義
- static int g_iCnt = 100;
- int main()
- {
- HANDLE hThread1 = INVALID_HANDLE_VALUE;
- HANDLE hThread2 = INVALID_HANDLE_VALUE;
- InitializeCriticalSection(&g_CriticalSection); // 初始化
- hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
- hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
- Sleep(4000); // 讓2個線程有足夠的時間執行完操作。
- CloseHandle(hThread1);
- CloseHandle(hThread2);
- DeleteCriticalSection(&g_CriticalSection); // 刪除
- system("PAUSE");
- return 0;
- }
- DWORD WINAPI Thread1(LPVOID lpParmeter)
- {
- while (true)
- {
- EnterCriticalSection(&g_CriticalSection); // 進入臨界區,獲得所有權,其他線程就等待
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "Thread1:" << g_iCnt-- << endl;
- LeaveCriticalSection(&g_CriticalSection); // 離開臨界區,釋放所有權
- }
- else
- {
- LeaveCriticalSection(&g_CriticalSection);
- break;
- }
- }
- return 0;
- }
- DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
- {
- while (true)
- {
- EnterCriticalSection(&g_CriticalSection);
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "thread2:" << g_iCnt-- << endl;
- LeaveCriticalSection(&g_CriticalSection);
- }
- else
- {
- LeaveCriticalSection(&g_CriticalSection);
- break;
- }
- }
- return 0;
- }
幾個注意的地方:
(1).比Mutex速度快;
(2).臨界區在線程內的分配必須是全局的;
(3). 臨界區一次只允許一個線程訪問;
4.信號量Semaphore
首先說說那些關於信號量那些不得不讓人傷心的事情,因為筆者大學不好學習,非常調皮,而信號量又是老師最討論及考試的話題之一,所以我覺得這個東西非常扯淡,非常影響情緒,於是放在最后。------以上是為題外話。
為什么大學老師總是喜歡信號量呢?
因為這是一個生產者-消費者模型,並且很多計算機問題都可以看做是生產者-消費者的問題,是同步最易理解的模型。
關於理論上的知識,我就不說了,書里面很多的。
還有我不是很想實現生產者-消費者的模型,就用其他例子代替了。這個有點不負責任。
- #include <Windows.h>
- #include <iostream>
- #include <vector>
- using namespace std;
- DWORD WINAPI Thread1(LPVOID lpParmeter);
- DWORD WINAPI Thread2(LPVOID lpParmeter);
- static HANDLE g_hSemaphore = INVALID_HANDLE_VALUE;; // 定義
- static int g_iCnt = 100;
- int main()
- {
- HANDLE hThread1 = INVALID_HANDLE_VALUE;
- HANDLE hThread2 = INVALID_HANDLE_VALUE;
- // HANDLE CreateSemaphore (
- // PSECURITY_ATTRIBUTE psa,
- // LONG lInitialCount, //開始時可供使用的資源數
- // LONG lMaximumCount, //最大資源數
- // PCTSTR pszName);
- g_hSemaphore = CreateSemaphore(NULL, 1, 1, "Semaphore");
- // 初始化有1個信號量。
- if (g_hSemaphore == INVALID_HANDLE_VALUE)
- {
- cout << "Failed to Create Semaphore!" << endl;
- return 0;
- }
- hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
- hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
- Sleep(4000); // 讓2個線程有足夠的時間執行完操作。
- CloseHandle(hThread1);
- CloseHandle(hThread2);
- system("PAUSE");
- return 0;
- }
- DWORD WINAPI Thread1(LPVOID lpParmeter)
- {
- while (true)
- {
- WaitForSingleObject(g_hSemaphore, INFINITE); // 釋放一個信號量
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "Thread1:" << g_iCnt-- << endl;
- ReleaseSemaphore(g_hSemaphore, 1, NULL); // 增加一個信號量
- }
- else
- {
- break;
- }
- }
- return 0;
- }
- DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
- {
- while (true)
- {
- WaitForSingleObject(g_hSemaphore, INFINITE);
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "thread2:" << g_iCnt-- << endl;
- ReleaseSemaphore(g_hSemaphore, 1, NULL);
- }
- else
- {
- break;
- }
- }
- return 0;
- }
幾個注意的地方:
信號量內核對象對線程的同步方式與前面幾種不同,它允許多個線程在同一時刻訪問某一資源,但是需要限制同一時刻訪問此資源的最大線程數目。
總結: 線程規模 = CPU 數 * 2 + 1
轉自