Mutex和Critical Section都是主要用於限制多線程(Multithread)對全局或共享的變量、對象或內存空間的訪問。下面是其主要的異同點(不一樣的地方用綠色表示)。ios
Mutex多線程
Critical Sectionapp
性能和速度函數
慢。性能
Mutex 是內核對象,相關函數的執行 (WaitForSingleObject,spa
ReleaseMutex)須要用戶模式(User Mode)到內核模式.net
(Kernel Mode)的轉換,在x86處理器上這種轉化通常要線程
發費600個左右的 CPU指令週期。設計
快。code
Critical Section自己不是內核對象,相關函數
(EnterCriticalSection,LeaveCriticalSection)
的調用通常都在用戶模式內執行,在x86處理器上
通常只須要發費9個左右的 CPU指令週期。只有
當想要得到的鎖正好被別的線程擁有時纔會退化
成和Mutex同樣,即轉換到內核模式,發費600個
左右的 CPU指令週期。
可否跨越進程(Process)邊界
能夠
不可
定義寫法
HANDLE hmtx;
CRITICAL_SECTION cs;
初始化寫法
hmtx= CreateMutex (NULL, FALSE, NULL);
InitializeCriticalSection(&cs);
結束清除寫法
CloseHandle(hmtx);
DeleteCriticalSection(&cs);
無限期等待的寫法
WaitForSingleObject (hmtx, INFINITE);
EnterCriticalSection(&cs);
0等待(狀態檢測)的寫法
WaitForSingleObject (hmtx, 0);
TryEnterCriticalSection(&cs);
任意時間等待的寫法
WaitForSingleObject (hmtx, dwMilliseconds);
不支持
鎖釋放的寫法
ReleaseMutex(hmtx);
LeaveCriticalSection(&cs);
可否被一道用於等待其餘內核對象
能夠(使用WaitForMultipleObjects,
WaitForMultipleObjectsEx,
MsgWaitForMultipleObjects,
MsgWaitForMultipleObjectsEx等等)
不可
當擁有鎖的線程死亡時
Mutex變成abandoned狀態,其餘的等待線程能夠得到鎖。
Critical Section的狀態不可知(undefined),
之後的動做就不能保證了。
本身會不會鎖住本身
不會(對已得到的Mutex,重複調用WaitForSingleObject不會
鎖住本身。但最後你別忘了要調用一樣次數的
ReleaseMutex)
不會(對已得到的Critical Section,重複調用
EnterCriticalSection不會鎖住本身。但最後
你別忘了要調用一樣次數的
LeaveCriticalSection)
下面是一些補充:
l 請先檢查你的設計,把沒必要要的全局或共享對象改成局部對象。全局的東西越少,出問題的可能就越小。
l 每次你使用EnterCriticalSection時,請不要忘了在函數的全部可能返回的地方都加上LeaveCriticalSection。對於Mutex也一樣。若你把這個問題和Win32 structured exception或C++ exception一塊兒考慮,你會發現問題並非那麼簡單。自定義一個封裝類多是一種解決方案,以Critical Section爲例的代碼以下所示:
class csholder
{
CRITICAL_SECTION *cs;
public:
csholder(CRITICAL_SECTION *c): cs(c)
{ EnterCriticalSection(cs); }
~csholder() { LeaveCriticalSection(cs); }
};
CRITICAL_SECTION some_cs;
void foo()
{
// ...
csholder hold_some(&some_cs);
// ... CS protected code here
// at return or if an exception happens
// hold_some's destructor is automatically called
}
l 根據你的互斥範圍需求的不一樣,把Mutex或Critical Section定義爲類的成員變量,或者靜態類變量。
l 若你想限制訪問的全局變量只有一個並且類型比較簡單(好比是LONG或PVOID型),你也可使用InterlockedXXX系列函數來保證一個線程寫多個線程讀。
Demo程序
#include <Windows.h>
#include <iostream>
using namespace std;
int index = 0;
// 臨界區結構對象
CRITICAL_SECTION g_cs;
HANDLE hMutex = NULL;
void changeMe()
{
cout << index++ << endl;
}
void changeMe2()
{
cout << index++ << endl;
}
void changeMe3()
{
cout << index++ << endl;
}
DWORD WINAPI th1(LPVOID lpParameter)
{
while(1)
{
Sleep(1600); //sleep 1.6 s
// 進入臨界區
EnterCriticalSection(&g_cs);
// 等待互斥對象通知
//WaitForSingleObject(hMutex, INFINITE);
// 對共享資源進行寫入操做
//cout << "a" << index++ << endl;
changeMe();
changeMe2();
changeMe3();
// 釋放互斥對象
//ReleaseMutex(hMutex);
// 離開臨界區
LeaveCriticalSection(&g_cs);
}
return 0;
}
DWORD WINAPI th2(LPVOID lpParameter)
{
while(1)
{
Sleep(2000); //sleep 2 s
// 進入臨界區
EnterCriticalSection(&g_cs);
// 等待互斥對象通知
//WaitForSingleObject(hMutex, INFINITE);
//cout << "b" << index++ << endl;
changeMe();
changeMe2();
changeMe3();
// 釋放互斥對象
//ReleaseMutex(hMutex);
// 離開臨界區 LeaveCriticalSection(&g_cs); } return 0; } int main(int argc, char* argv[]) { // 建立互斥對象 //hMutex = CreateMutex(NULL, TRUE, NULL); // 初始化臨界區 InitializeCriticalSection(&g_cs); HANDLE hThread1; HANDLE hThread2; hThread1 = CreateThread(NULL, 0, th1, NULL, 0, NULL); hThread2 = CreateThread(NULL, 0, th2, NULL, 0, NULL); int k; cin >> k; printf("Hello World!\n"); return 0; } --------------------- 做者:LoveApp_Han 來源:CSDN 原文:https://blog.csdn.net/xdrt81y/article/details/17005235 版權聲明:本文爲博主原創文章,轉載請附上博文連接!