C++ 訊號量 多執行緒同步互斥
阿新 • • 發佈:2019-02-07
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">訊號量(Semaphores) </span>
訊號量物件對執行緒的同步方式與前面幾種方法不同,訊號允許多個執行緒同時使用共享資源,這與作業系統中的PV操作相同。它指出了同時訪問共享資源的執行緒 最大數目。它允許多個執行緒在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大執行緒數目。在用CreateSemaphore()建立訊號量 時即要同時指出允許的最大資源計數和當前可用資源計數。一般是將當前可用資源計數設定為最大資源計數,每增加一個執行緒對共享資源的訪問,當前可用資源計數 就會減1,只要當前可用資源計數是大於0的,就可以發出訊號量訊號。但是當前可用計數減小到0時則說明當前佔用資源的執行緒數已經達到了所允許的最大數目, 不能在允許其他執行緒的進入,此時的訊號量訊號將無法發出。執行緒在處理完共享資源後,應在離開的同時通過ReleaseSemaphore()函式將當前可 用資源計數加1。在任何時候當前可用資源計數決不可能大於最大資源計數。 PV操作及訊號量的概念都是由荷蘭科學家E.W.Dijkstra提出的。訊號量S是一個整數,S大於等於零時代表可供併發程序使用的資源實體數,但S小於零時則表示正在等待使用共享資源的程序數。 P操作 申請資源: (1)S減1;
(2)若S減1後仍大於等於零,則程序繼續執行;
(3)若S減1後小於零,則該程序被阻塞後進入與該訊號相對應的佇列中,然後轉入程序排程。
V操作 釋放資源: (1)S加1;
(2)若相加結果大於零,則程序繼續執行;
(3)若相加結果小於等於零,則從該訊號的等待佇列中喚醒一個等待程序,然後再返回原程序繼續執行或轉入程序排程。
訊號量包含的幾個操作原語:
CreateSemaphore() 建立一個訊號量
OpenSemaphore() 開啟一個訊號量
ReleaseSemaphore() 釋放訊號量
WaitForSingleObject() 等待訊號量
#include <Windows.h> #include <stdio.h> HANDLE hSemaphore = NULL; const char* strSemaphoreName = "MySemaphore"; const int threads_num = 50; HANDLE Threads[threads_num]; bool bExitThreads = FALSE; void WINAPI ThreadFun(void* param) { printf("執行緒 %u 開始執行\n", GetCurrentThreadId()); WaitForSingleObject(hSemaphore,INFINITE); printf("執行緒 %u 獲得訊號量,繼續執行\n", GetCurrentThreadId()); while(!bExitThreads) { Sleep(10); } long dwSem = 0; if (!ReleaseSemaphore(hSemaphore, 1, &dwSem)) { if (0 == GetLastError()) { printf("當前可用資源數:20\n"); return; } } printf("當前可用資源數:%u\n", dwSem); } void creatThreads() { DWORD dwThreadID = 0; for (int i =0; i < threads_num; ++i) { Threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFun, NULL, 0, &dwThreadID); if (!Threads[i]) { printf("建立執行緒失敗!\n"); } printf("執行緒 %u 建立成功\n", dwThreadID); } } void main() { hSemaphore = CreateSemaphoreA(NULL, 0, 20, strSemaphoreName); if(NULL == (hSemaphore = OpenSemaphoreA(SEMAPHORE_MODIFY_STATE , FALSE, strSemaphoreName))) { printf("開啟訊號量物件失敗 , 錯誤ID:%u\n", GetLastError()); return; } creatThreads(); bExitThreads = true; WaitForMultipleObjects(threads_num, Threads, TRUE, INFINITE); }