Mutex和Critical Section都是主要用於限制多線程(Multithread)對全局或共享的變量、對象或內存空間的訪問。下面是其主要的異同點(不同的地方用黑色表示)。
Mutex | Critical Section | |
---|---|---|
性能和速度 | 慢。Mutex 是內核對象,相關函數的執行 (WaitForSingleObject,eleaseMutex)需要用戶模式(User Mode)到內核模式(Kernel Mode)的轉換,在x86處理器上這種轉化一般要發費600個左右的 CPU指令周期 | 快,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狀態,其他的等待線程可以獲得鎖 | CriticalSection的狀態不可知(undefined),以后的動作就不能保證了。 |
有人測試結果,CriticalSection用時速度比Mutex快不少。
http://blog.csdn.net/dreamfreelancer/article/details/4237272
windows下100萬次加/解鎖測試:
CriticalSection用時:31ms
Mutex用時:953ms
結論:CriticalSection性能遠遠高於Mutex(高出約30倍)。因此,在能用CriticalSection時絕不用Mutex,當然,后者可命名,而前者不行,因此,Mutex可用於進程間通信,但CriticalSection通常只能用於線程間通信。
另外,Windows上Mutex和CriticalSection都是缺省Recursive的(且不能被改變,如要實現non-recursive互斥,得用Semophore),就是同一線程在獲得鎖后,再次加鎖不會導致阻塞,這在Linux下需要指定。 但Mutex和CriticalSection行為還是存在差異,如果在同一線程內進行了Recursive的加,解鎖操作,若因為程序錯誤導致解鎖操作次數比加鎖操作多,對於Mutex,這不會有任何問題(linux和Windows都是如此),但CriticalSection表現卻不同,多於必要的Unlock操作會導致下次Lock操作被阻塞。
Demo code CRITICAL_SECTION
#include <windows.h>
#include "stdio.h"
CRITICAL_SECTION g_cs;
LRESULT WINAPI WriteThread(PVOID arg)
{
EnterCriticalSection(&g_cs);
printf("WriteThread \n");
LeaveCriticalSection(&g_cs);
return 0;
}
LRESULT WINAPI ReadThread(PVOID arg)
{
EnterCriticalSection(&g_cs);
printf("ReadThread \n");
LeaveCriticalSection(&g_cs);
return 0;
}
int main1()
{
HANDLE hThreadArray[2];
InitializeCriticalSection(&g_cs);
hThreadArray[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WriteThread, NULL, 0, NULL);
hThreadArray[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReadThread, NULL, 0, NULL);
WaitForMultipleObjects(2, hThreadArray, TRUE, INFINITE);
DeleteCriticalSection(&g_cs);
getchar();
return 0;
}
Demo code Mutex
#include <windows.h>
#include "stdio.h"
HANDLE hMutex = NULL;
LRESULT WINAPI WriteThread2(PVOID arg)
{
WaitForSingleObject(hMutex, INFINITE);
printf("WriteThread2 \n");
ReleaseMutex(hMutex);
return 0;
}
LRESULT WINAPI ReadThread2(PVOID arg)
{
WaitForSingleObject(hMutex, INFINITE);
printf("ReadThread2 \n");
ReleaseMutex(hMutex);
return 0;
}
int main()
{
HANDLE hThreadArray[2];
hMutex = CreateMutex(NULL, FALSE, NULL);
hThreadArray[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WriteThread2, NULL, 0, NULL);
hThreadArray[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReadThread2, NULL, 0, NULL);
WaitForMultipleObjects(2, hThreadArray, TRUE, INFINITE);
getchar();
CloseHandle(hMutex);
return 0;
}