线程同步(临界区、互斥量、事件、信号量)
1、為什么線程要同步?
#include<windows.h> #include<iostream> using namespace std; DWORD WINAPI ThreadFunc1(PVOID pvParam) {cout << "線程1:創建成功!" << endl;return 0; } DWORD WINAPI ThreadFunc2(PVOID pvParam) {cout << "線程2:創建成功!" << endl;return 0; } DWORD WINAPI ThreadFunc3(PVOID pvParam) {cout << "線程3:創建成功!" << endl;return 0; } int main(int argc, char* argv[]) {HANDLE ThreadHandle1, ThreadHandle2, ThreadHandle3;ThreadHandle1 = CreateThread(NULL, 0, ThreadFunc1, NULL, 0, NULL);ThreadHandle2 = CreateThread(NULL, 0, ThreadFunc2, NULL, 0, NULL);ThreadHandle3 = CreateThread(NULL, 0, ThreadFunc3, NULL, 0, NULL);getchar();return 0; }
舉一個例子,創建三個線程。根據結果得知:操作系統隨機調用線程,不能預知線程的執行順序。
2、Windows線程同步方法主要有臨界區、事件、互斥量、信號量四種。
3、臨界區
利用臨界區相關API函數,上述程序可以修改為:
#include<windows.h> #include<iostream> using namespace std; CRITICAL_SECTION cs; DWORD WINAPI ThreadFunc1(PVOID pvParam) {EnterCriticalSection(&cs);cout << "線程1:創建成功!" << endl;LeaveCriticalSection(&cs);return 0; } DWORD WINAPI ThreadFunc2(PVOID pvParam) {EnterCriticalSection(&cs);cout << "線程2:創建成功!" << endl;LeaveCriticalSection(&cs);return 0; } DWORD WINAPI ThreadFunc3(PVOID pvParam) {EnterCriticalSection(&cs);cout << "線程3:創建成功!" << endl;LeaveCriticalSection(&cs);return 0; } int main(int argc, char* argv[]) {InitializeCriticalSection(&cs);HANDLE ThreadHandle1, ThreadHandle2, ThreadHandle3;ThreadHandle1 = CreateThread(NULL, 0, ThreadFunc1, NULL, 0, NULL);ThreadHandle2 = CreateThread(NULL, 0, ThreadFunc2, NULL, 0, NULL);ThreadHandle3 = CreateThread(NULL, 0, ThreadFunc3, NULL, 0, NULL);getchar();DeleteCriticalSection(&cs);return 0; }
雖然臨界區同步速度很快,但是只能用來同步本進程內的線程,不能同步多個進程中的線程。
4、兩個重要的同步等待函數
上述的程序代碼又可以改寫為:
#include<windows.h> #include<iostream> using namespace std; HANDLE ThreadHandle1, ThreadHandle2, ThreadHandle3; DWORD WINAPI ThreadFunc1(PVOID pvParam) {cout << "線程1:創建成功!" << endl;return 0; } DWORD WINAPI ThreadFunc2(PVOID pvParam) {WaitForSingleObject(ThreadHandle1, INFINITE);cout << "線程2:創建成功!" << endl;return 0; } DWORD WINAPI ThreadFunc3(PVOID pvParam) {WaitForSingleObject(ThreadHandle2, INFINITE);cout << "線程3:創建成功!" << endl;return 0; } int main(int argc, char* argv[]) {ThreadHandle1 = CreateThread(NULL, 0, ThreadFunc1, NULL, 0, NULL);ThreadHandle2 = CreateThread(NULL, 0, ThreadFunc2, NULL, 0, NULL);ThreadHandle3 = CreateThread(NULL, 0, ThreadFunc3, NULL, 0, NULL);getchar();return 0; }
線程1直接創建,線程2等待線程1創建,線程3等待線程2創建。
5、互斥量
上述程序又可以改寫為:
#include<windows.h> #include<iostream> using namespace std; HANDLE ThreadHandle1, ThreadHandle2, ThreadHandle3; HANDLE ThreadMutex; DWORD WINAPI ThreadFunc1(PVOID pvParam) {WaitForSingleObject(ThreadMutex, INFINITE);cout << "線程1:創建成功!" << endl;ReleaseMutex(ThreadMutex);return 0; } DWORD WINAPI ThreadFunc2(PVOID pvParam) {WaitForSingleObject(ThreadMutex, INFINITE);cout << "線程2:創建成功!" << endl;ReleaseMutex(ThreadMutex);return 0; } DWORD WINAPI ThreadFunc3(PVOID pvParam) {WaitForSingleObject(ThreadMutex, INFINITE);cout << "線程3:創建成功!" << endl;ReleaseMutex(ThreadMutex);return 0; } int main(int argc, char* argv[]) {ThreadMutex = CreateMutex(NULL, false, "tMutex");ThreadHandle1 = CreateThread(NULL, 0, ThreadFunc1, NULL, 0, NULL);ThreadHandle2 = CreateThread(NULL, 0, ThreadFunc2, NULL, 0, NULL);ThreadHandle3 = CreateThread(NULL, 0, ThreadFunc3, NULL, 0, NULL);getchar();return 0; }
注意CreateMutex第二個參數為false,說明當前主線程并不擁有互斥對象。
6、事件
上述程序可以改為:
#include<windows.h> #include<iostream> using namespace std; HANDLE ThreadHandle1, ThreadHandle2, ThreadHandle3; HANDLE ThreadEvent; DWORD WINAPI ThreadFunc1(PVOID pvParam) {WaitForSingleObject(ThreadEvent, INFINITE);cout << "線程1:創建成功!" << endl;SetEvent(ThreadEvent);return 0; } DWORD WINAPI ThreadFunc2(PVOID pvParam) {WaitForSingleObject(ThreadEvent, INFINITE);cout << "線程2:創建成功!" << endl;SetEvent(ThreadEvent);return 0; } DWORD WINAPI ThreadFunc3(PVOID pvParam) {WaitForSingleObject(ThreadEvent, INFINITE);cout << "線程3:創建成功!" << endl;SetEvent(ThreadEvent);return 0; } int main(int argc, char* argv[]) {ThreadEvent = CreateEvent(NULL, false, true, "tEvent");ThreadHandle1 = CreateThread(NULL, 0, ThreadFunc1, NULL, 0, NULL);ThreadHandle2 = CreateThread(NULL, 0, ThreadFunc2, NULL, 0, NULL);ThreadHandle3 = CreateThread(NULL, 0, ThreadFunc3, NULL, 0, NULL);getchar();return 0; }
注意CreateEvent中的第三個參數要設置為true,一開始就是有信號的。
其中,每個線程函數還可以改寫為:
7、信號量
信號量—API函數 創建信號量 HANDLE CreateSemaphore(PSECURITY_ATTRIBUTES psa,LONG lInitialCount, 當前可用資源數LONG lMaximumCount, 允許最大資源數PCTSTR pszName); 為現有的一個已命名信號機對象創建一個新句柄 HANDLE OpenSemaphore(DWORD fdwAccess,BOOL bInheritHandle,PCTSTR pszName); SEMAPHORE_ALL_ACCESS 要求對信號量的完全訪問 SEMAPHORE_MODIFY_STATE 允許使用ReleaseSemaphore函數 SYNCHRONIZE 允許使用信號量同步 釋放信號量 ReleaseSemaphore(HANDLE hSem,LONG lReleaseCount,PLONG plPreviousCount);上述程序可以改寫為:
#include<windows.h> #include<iostream> using namespace std; HANDLE ThreadHandle1, ThreadHandle2, ThreadHandle3; HANDLE ThreadSemaphore; LONG a = 0; DWORD WINAPI ThreadFunc1(PVOID pvParam) {WaitForSingleObject(ThreadSemaphore, INFINITE);cout << "線程1:創建成功!" << endl;ReleaseSemaphore(ThreadSemaphore, 1, &a);return 0; } DWORD WINAPI ThreadFunc2(PVOID pvParam) {WaitForSingleObject(ThreadSemaphore, INFINITE);cout << "線程2:創建成功!" << endl;ReleaseSemaphore(ThreadSemaphore, 1, &a);return 0; } DWORD WINAPI ThreadFunc3(PVOID pvParam) {WaitForSingleObject(ThreadSemaphore, INFINITE);cout << "線程3:創建成功!" << endl;ReleaseSemaphore(ThreadSemaphore, 1, &a);return 0; } int main(int argc, char* argv[]) {ThreadSemaphore = CreateSemaphore(NULL, 1, 3, NULL);ThreadHandle1 = CreateThread(NULL, 0, ThreadFunc1, NULL, 0, NULL);ThreadHandle2 = CreateThread(NULL, 0, ThreadFunc2, NULL, 0, NULL);ThreadHandle3 = CreateThread(NULL, 0, ThreadFunc3, NULL, 0, NULL);getchar();return 0; }
注意CreateSemaphore中的參數設置,為了防止亂序產生,當前可用的資源數應該設置為1。
8、總結
互斥量、事件、信號量都是內核對象,可用于進程間的線程同步;臨界區只能用于進程內的線程同步。雖然在同一個進程內同步時,互斥量和臨界區的功能相似,但是臨界區的性能更好。
事件和其他幾個同步方法的不同在于事件的主要作用不是保護共享資源,而是用于等待某個事件和在特定的事件發生時的發送信號,以協調線程之間的動作。
信號量與其他同步方法的區別在于它允許一個以上的線程同時訪問共享資源,而其他線程同步方法都保證同時只能有一個線程訪問共享資源。信號量的主要功能是用于資源計數。
總結
以上是生活随笔為你收集整理的线程同步(临界区、互斥量、事件、信号量)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于数字石油,为什么智慧油田能拉动产业变
- 下一篇: 长庆企业信息化管理课件_长庆油田信息化建