windows多線程(六) 互斥量Mutex與關鍵段CriticalSection比較
一、關鍵段CS 和 互斥量Mutex 的相同點:都有線程擁有權
關鍵段和互斥量都有線程擁有權,即可以被一個線程擁有。在 前面講關鍵段CS的文章中有說到,關鍵段結構體的第四個參數保存著擁有該關鍵段的線程的句柄,具體如下:
typedef struct _RTL_CRITICAL_SECTION {
PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
//
// The following three fields control entering and exiting the critical
// section for the resource
//
LONG LockCount;
LONG RecursionCount;
HANDLE OwningThread; // from the thread's ClientId->UniqueThread
HANDLE LockSemaphore;
ULONG_PTR SpinCount; // force size on 64-bit systems when packed
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
-
第一個參數:PRTL_CRITICAL_SECTION_DEBUG DebugInfo; 調試的時候用的,先不做介紹。
-
第二個參數:LONG LockCount; 初始化為-1,n表示有n個線程在等待。
-
第三個參數:LONG RecursionCount; 表示該關鍵段的擁有線程對此資源獲得關鍵段次數,初為0。
-
第四個參數:HANDLE OwningThread; 即擁有該關鍵段的線程句柄
-
第五個參數:HANDLE LockSemaphore; 實際上是一個自復位事件。
-
第六個參數:ULONG_PTR SpinCount; 旋轉鎖的設置,用于多處理器。
現在我們來分析以下程序:
#include<iostream>
#include <windows.h>
using namespace std;
const unsigned int THREAD_NUM = 10;
unsigned int g_Count = 0;
CRITICAL_SECTION cs;
DWORD WINAPI ThreadFunc(LPVOID);
int main()
{
InitializeCriticalSection(&cs);
HANDLE hThread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i++)
{
EnterCriticalSection(&cs); // 進入關鍵段,執行這一句時主線程就獲得了這個關鍵段的擁有權。
hThread[i] = CreateThread(NULL, 0, ThreadFunc,0, 0, NULL);
}
WaitForMultipleObjects(THREAD_NUM, hThread,true,INFINITE);
cout << THREAD_NUM << " 個線程全部返回" << endl;
return 0;
}
DWORD WINAPI ThreadFunc(LPVOID p)
{
LeaveCriticalSection(&cs); // 離開關鍵段
Sleep(50);
EnterCriticalSection(&cs); // 進入關鍵段
cout<<"g_Count 的值為:"<<g_Count++<<endl;
LeaveCriticalSection(&cs); // 離開關鍵段
Sleep(50);
return 0;
}
如下圖所示加上兩個斷點進行調試,正常來說程序應該是依次經過兩個斷點,但是調試時我們發現,程序會多次重復進入第一個斷點,這是因為執行到第一個斷點式時主線程就獲得了這個關鍵段的擁有權。
同樣地,Mutex也擁有線程所有權,需要了解互斥量看這里。和上面一樣,我們寫這樣一個程序
#include <iostream>
#include <windows.h>
using namespace std;
const unsigned int THREAD_NUM = 10;
unsigned int g_Count = 0;
CRITICAL_SECTION cs;
HANDLE g_Mutex;
DWORD WINAPI ThreadFunc(LPVOID);
int main()
{
InitializeCriticalSection(&cs);
g_Mutex = CreateMutex(NULL, false, NULL); //初始化互斥量為觸發狀態
HANDLE hTread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM;i++)
{
WaitForSingleObject(g_Mutex, INFINITE); //等待互斥量觸發
hTread[i] = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL);
}
WaitForMultipleObjects(THREAD_NUM, hTread, true, INFINITE);
cout << THREAD_NUM << " 個線程全部返回" << endl;
return 0;
}
DWORD WINAPI ThreadFunc(LPVOID p)
{
//ReleaseMutex(g_Mutex);
Sleep(50);
EnterCriticalSection(&cs); // 進入關鍵段
cout << "g_Count 的值為:" << g_Count++ << endl;
LeaveCriticalSection(&cs); // 離開關鍵段
Sleep(50);
ReleaseMutex(g_Mutex); //觸發互斥量
return 0;
}
同樣地,我們在程序中下兩個斷點,同樣地程序會不經過第二個斷點,而重復經過第一個斷點。
前面關鍵段和互斥量兩篇文章我們說了關鍵段CS和互斥量Mutex不能做到線程同步,只能做到臨界資源互斥訪問,就是因為,他它們都有線程擁有權的原因。
二、關鍵段CS 和 互斥量Mutex 的不同點:由于互斥量常用于多進程之間的線程互斥,所以它比關鍵段還多一個很有用的特性——“遺棄”情況的處理。
看下面的程序:
程序一:
#include <stdio.h>
#include <windows.h>
const char MutexName[] = "MyMutex"; //互斥量名字
int main()
{
HANDLE hMutex = CreateMutex(NULL, TRUE, MutexName); //創建互斥量并初始化為未觸發狀態
printf("互斥量已經創建,按任意鍵觸發\n");
getch();
exit(0); //在互斥量觸發前退出程序。
//ReleaseMutex(hMutex); // 觸發互斥量
printf("互斥量已經被觸發\n");
CloseHandle(hMutex);
return 0;
}
程序二:
#include <stdio.h>
#include <windows.h>
const char MutexName[] = "MyMutex"; //互斥量名字
int main()
{
HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, TRUE, MutexName); //打開互斥量
if (NULL != hMutex)
{
printf("打開互斥量成功,等待互斥量被觸發\n");
DWORD mRes = WaitForSingleObject(hMutex, INFINITE); // 等待互斥量被觸發
if (WAIT_ABANDONED == mRes) //判斷互斥量是否被遺棄
{
printf("互斥量被遺棄。\n");
}
//printf("互斥量已經被觸發\n");
}
else
{
printf("互斥量打開失敗。\n");
}
CloseHandle(hMutex);
return 0;
}
先運行,程序一,然后運行程序二,如下圖所示。
此時在,程序一中按任意鍵,使程序一在互斥量未觸發之前退出,程序二輸出如下:
這篇是邊學邊寫出來的可能有不正確的地方,歡迎指出!!!!!
智能推薦
多線程六:死鎖例子與排查
死鎖產生情況:雙方互相持有對方的鎖的情況 死鎖示例代碼: 運行結果: 排查: 使用jdk自帶工具進行排查 執行jps指令,可以查看當前運行的線程: 可以看到Run線程的id值為3684。在執行jstack命令,查看結果:...
經典線程同步 互斥量Mutex的使用分析
互斥量(mutex)內核對象用來確保一個線程獨占對一個資源的訪問。 互斥量對象包含一個使用計數、線程ID以及一個遞歸計數。 互斥量與關鍵段的行為完全相同。但是,互斥量是內核對象,而關鍵段是用戶模式下的同步對象。 ...
多線程(2)---(同步&互斥&互斥量)
上一個博客我們學習了線程的創建,如如何查看線程ID,線程與進程之間的區別等等,可以參考上篇博客線程(1)。而這一篇博客我們繼續來學習線程,本篇博客我們的目標是: 1、學會線程同步 2、學會使用互斥量、條件變量 線程同步與互斥 mutex(互斥量) 大部分情況下,線程使用的數據都是局部變量,變量的地址空間在棧空間內,這種情況...
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
猜你喜歡
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...