執行緒同步的四種方式(一)
阿新 • • 發佈:2019-01-24
併發concurent與並行parallel的區別:
- 互斥物件
首先我們需要建立CreateMutex一把互斥物件,我們可以指明當前執行緒是否擁有它,互斥物件完全就像一把鑰匙一樣,我們用WaitForSignalObject來等待這把鑰匙,但是這把鑰匙被等到並且使用後必須釋放-----ReleaseMutex ,不然別人永遠無法等到。這樣從等待到釋放中間的程式碼段永遠都是隻有一個執行緒在執行,也就形成了互斥控制。當然互斥物件的控制代碼是要關閉的CloseHandle。
#include<windows.h> #include<iostream> using namespace std; int ticket = 100; HANDLE hMutex; //定義互斥物件 DWORD WINAPI FuncProc1(LPVOID lpParameter); DWORD WINAPI FuncProc2(LPVOID lpParameter); int main() { hMutex = CreateMutex(NULL, FALSE, NULL); //定義互斥物件,並讓該執行緒不擁有它 HANDLE hThread1 = CreateThread(NULL, 0, FuncProc1, NULL, 0, NULL); HANDLE hThread2 = CreateThread(NULL,0, FuncProc2, NULL, 0, NULL); CloseHandle(hThread1); CloseHandle(hThread2); Sleep(1000); //讓主執行緒睡眠1秒 return 0; } DWORD WINAPI FuncProc1(LPVOID lpParameter) { while (true) { WaitForSingleObject(hMutex, INFINITE); if (ticket > 0) { Sleep(1); cout << "ticket1 :" << ticket-- << endl; } else break; ReleaseMutex(hMutex); } return 0; } DWORD WINAPI FuncProc2(LPVOID lpParameter) { while (true) { WaitForSingleObject(hMutex, INFINITE); //申請互斥物件的所有權 if (ticket > 0) { Sleep(1); cout << "ticket2 :" << ticket-- << endl; } else break; ReleaseMutex(hMutex); //釋放互斥物件的所有權 } return 0; }
注意:
雖然改程式執行結果是某一條執行緒執行完然後第二條執行緒執行,如此往復,但是這不是同步,因為我們沒法控制到底一開始是誰先執行,(我們只是控制了輪流次序)。
- 事件
首先我們需要建立CreateEvent一個事件物件,它的使用方式是觸發方式,要想被WaitForSingleObject等待到該事件物件必須是有訊號的,事件要想有訊號可以用SetEvent手動置為有訊號,要想事件物件無訊號可以使用ResetEvent(或者在建立事件物件時就宣告),該事件物件在WaitForSingleObject後自動置為無訊號,見上面CreateEvent第二個引數),打個小小比方,手動置位事件相當於教室門,教室門一旦開啟(被觸發),所以有人都可以進入直到老師去關上教室門(事件變成未觸發)。自動置位事件就相當於醫院裡拍X光的房間門,門開啟後只能進入一個人,這個人進去後會將門關上,其它人不能進入除非門重新被開啟(事件重新被觸發)。當然事件物件的控制代碼是要關閉的CloseHandle。
#include<windows.h> #include<iostream> using namespace std; int ticket = 100; HANDLE g_hEvent; DWORD WINAPI FuncProc1(LPVOID lpParameter); DWORD WINAPI FuncProc2(LPVOID lpParameter); int main() { //引數意義:預設安全性,自動重置事件,初始時該事件物件就有訊號 g_hEvent = CreateEvent(NULL, FALSE, TRUE, NULL); HANDLE hThread1 = CreateThread(NULL, 0, FuncProc1, NULL, 0, NULL); HANDLE hThread2 = CreateThread(NULL,0, FuncProc2, NULL, 0, NULL); CloseHandle(hThread1); CloseHandle(hThread2); Sleep(1000); //讓主執行緒睡眠1秒 CloseHandle(g_hEvent); return 0; } DWORD WINAPI FuncProc1(LPVOID lpParameter) { while (true) { WaitForSingleObject(g_hEvent, INFINITE); //申請事件物件(申請鑰匙,持有鑰匙) if (ticket > 0) { Sleep(1); cout << "ticket1 :" << ticket-- << endl; SetEvent(g_hEvent); //(放棄鑰匙,不在擁有) } else { SetEvent(g_hEvent); //設定為有訊號 break; } } return 0; } DWORD WINAPI FuncProc2(LPVOID lpParameter) { while (true) { WaitForSingleObject(g_hEvent, INFINITE); //申請事件物件(申請鑰匙,持有鑰匙) if (ticket > 0) { Sleep(1); cout << "ticket2 :" << ticket-- << endl; SetEvent(g_hEvent); //(放棄鑰匙,不在擁有) } else { SetEvent(g_hEvent); //設定為有訊號 break; } } return 0; }
改進:具有嚴格的同步控制
#include<windows.h>
#include<iostream>
using namespace std;
int ticket = 100;
HANDLE g_hEvent1;
HANDLE g_hEvent2;
DWORD WINAPI FuncProc1(LPVOID lpParameter);
DWORD WINAPI FuncProc2(LPVOID lpParameter);
int main()
{
g_hEvent1 = CreateEvent(NULL, FALSE, TRUE, NULL); //建立事件物件
g_hEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL); //建立事件物件
HANDLE hThread1 = CreateThread(NULL, 0, FuncProc1, NULL, 0, NULL);
HANDLE hThread2 = CreateThread(NULL,0, FuncProc2, NULL, 0, NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
Sleep(1000); //讓主執行緒睡眠1秒
CloseHandle(g_hEvent1);
CloseHandle(g_hEvent2);
return 0;
}
DWORD WINAPI FuncProc1(LPVOID lpParameter) {
while (true) {
WaitForSingleObject(g_hEvent1, INFINITE); //申請事件物件(申請鑰匙,持有鑰匙)
if (ticket > 0) {
Sleep(1);
cout << "ticket1 :" << ticket-- << endl;
SetEvent(g_hEvent2); //讓執行緒2執行
}
else
{
SetEvent(g_hEvent2); //讓執行緒2執行
break;
}
}
return 0;
}
DWORD WINAPI FuncProc2(LPVOID lpParameter) {
while (true) {
WaitForSingleObject(g_hEvent2, INFINITE); //申請事件物件(申請鑰匙,持有鑰匙)
if (ticket > 0) {
Sleep(1);
cout << "ticket2 :" << ticket-- << endl;
SetEvent(g_hEvent1); //讓執行緒1執行
}
else
{
SetEvent(g_hEvent1); //讓執行緒1執行
break;
}
}
return 0;
}
- 臨界區
#include<iostream>
#include "windows.h"
using namespace std;
DWORD WINAPI FunProc1(LPVOID lpParameter);
DWORD WINAPI FunProc2(LPVOID lpParameter);
int ticket = 1000;
CRITICAL_SECTION g_cs;
int main()
{
InitializeCriticalSection(&g_cs); //初始化臨界區
HANDLE hThread1 = CreateThread(NULL, 0, FunProc1, NULL, 0, NULL);
HANDLE hThread2 = CreateThread(NULL, 0, FunProc2, NULL, 0, NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
Sleep(1000);
DeleteCriticalSection(&g_cs); //刪除臨界區
return 0;
}
DWORD WINAPI FunProc1(LPVOID lpParameter)
{
while (TRUE) {
EnterCriticalSection(&g_cs); //進入臨界區
Sleep(1);
if (ticket > 0) {
Sleep(1);
cout << "ticket1: " << ticket-- << endl;
LeaveCriticalSection(&g_cs); //離開臨界區
}
else {
LeaveCriticalSection(&g_cs); //離開
break;
}
}
return 0;
}
DWORD WINAPI FunProc2(LPVOID lpParameter)
{
while (TRUE) {
EnterCriticalSection(&g_cs);
Sleep(1);
if (ticket > 0) {
Sleep(1);
cout << "ticket2: " << ticket-- << endl;
LeaveCriticalSection(&g_cs);
}
else {
LeaveCriticalSection(&g_cs);
break;
}
}
return 0;
}