日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

线程同步(临界区、互斥量、事件、信号量)

發布時間:2024/3/12 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线程同步(临界区、互斥量、事件、信号量) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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函數 定義臨界區對象(通常全局變量) CRITICAL_SECTION cs 臨界區對象初始化 InitializeCriticalSection(&cs) 進入臨界區 EnterCriticalSection(&cs) 離開臨界區 LeaveCriticalSection(&cs) 釋放臨界區對象 DeleteCriticalSection(&cs)

利用臨界區相關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、兩個重要的同步等待函數

DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds 0:立即返回;INFINITE:永遠等待); 返回值: WAIT_OBJECT_0 線程等待的對象變為已通知狀態 WAIT_TIMEOUT 超時 WAIT_FAILED 將無效的句柄傳遞給WaitForSingleObjectDWORD WaitForMultipleObject(DWORD dwCount, 指明內核對象的數量CONST HANDLE* phHandle, 指向內核對象句柄的數組指針BOOL fWaitAll, true:所有對象變為已通知前,不允許調用線程DWORD dwMilliseconds);

上述的程序代碼又可以改寫為:

#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、互斥量

互斥量—API函數 互斥量的創建,返回句柄 HANDLE CreateMutex(PSECURITY_ATTRIBUTES psa, 安全屬性的指針BOOL bInitialOwner, 初始化互斥對象的所有者PCTSTR pszName 指向互斥對象名的指針); 為現有的一個已命名互斥對象創建一個新句柄 HANDLE openMutex(DOWRD fdwAccess,BOOL bInheritHandle,PCTSTR pszName); 釋放互斥量 HANDLE ReleaseMutex(HANDLE hMutex); 等待互斥量 DOWRD WaitForSingleObject(HANDLE hHandle,DOWRD dwMilliseconds);

上述程序又可以改寫為:

#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、事件

事件—API函數 創建事件內核對象,返回句柄 HANDLE CreateEvent(PSECURITY_ATTRIBUTES psa, 安全屬性BOOL fManuaResrt, 復位方式,false自動BOOL fInitialState, 初始狀態,true有信號PCTSTR pszName 對象名稱); 打開一個已經存在的命名事件對象 HANDLE OpenEvent(DOWRD fdwAccess,BOOL fInherit,PCTSTR pszName); EVENT_ALL_ACCESS 要求對事件對象進行完全訪問 EVENT_MODIFY_STATE 允許SetEvent和ResetEvent函數 SYNCHRONIZE 允許事件對象的使用同步 將事件設置為已通知狀態 BOOL SetEvent(HANDLE hEvent); 將事件設置為未通知狀態 BOOL ResetEvent(HANDLE hEvent);

上述程序可以改為:

#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,一開始就是有信號的。
其中,每個線程函數還可以改寫為:

DWORD WINAPI ThreadFunc1(PVOID pvParam) {HANDLE event1=OpenEvent(EVENT_ALL_ACCESS,true,"tEvent");WaitForSingleObject(event1,INFINITE);cout<<"線程1:創建成功!"<<endl;SetEvent(ThreadEvent);return 0; }

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、總結
互斥量、事件、信號量都是內核對象,可用于進程間的線程同步;臨界區只能用于進程內的線程同步。雖然在同一個進程內同步時,互斥量和臨界區的功能相似,但是臨界區的性能更好。
事件和其他幾個同步方法的不同在于事件的主要作用不是保護共享資源,而是用于等待某個事件和在特定的事件發生時的發送信號,以協調線程之間的動作。
信號量與其他同步方法的區別在于它允許一個以上的線程同時訪問共享資源,而其他線程同步方法都保證同時只能有一個線程訪問共享資源。信號量的主要功能是用于資源計數。

總結

以上是生活随笔為你收集整理的线程同步(临界区、互斥量、事件、信号量)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。