互斥器核心物件
多個執行緒訪問同一資源時,為了保證資料的一致性,最簡單的方式就是使用 mutex(互斥鎖)。
互斥器保證執行緒擁有對單個資源的互斥訪問權。互斥物件類似於關鍵**區,但它是乙個核心物件。
互斥器不同於其他核心物件,它有乙個「執行緒所有權」的概念。它如果被某個執行緒等待成功,就屬於該執行緒。
互斥器的使用規則如下:
1. 如果執行緒id是0(無效id),互斥物件不被任何執行緒擁有,並且發出該互斥物件的通知訊號。
2. 如果id是非0數字,那麼乙個執行緒可以擁有互斥物件,並且不發出該互斥物件的通知訊號。
3. 互斥器有乙個遞迴計數器。如果執行緒已經擁有了互斥器,而它再次等待該互斥器,則馬上成功返回;而且遞迴計數器加1。
通過createmutex建立。releasemutex用來釋放互斥器。如果執行緒擁有互斥器,則首先把遞迴計數器減1,如果減到0,則執行緒釋放互斥器,或者說互斥器的所屬執行緒為空。此後其他執行緒就可以等待得到該互斥器了。但是如果乙個執行緒releasemutex了乙個本來不歸他所有的互斥器,則不會有任何效果。
互斥器常用於保護由多個執行緒訪問的核心塊。互斥器保證了訪問記憶體塊的任何執行緒擁有對該記憶體塊的獨佔訪問。
其成功等待***是將所有權賦予執行緒,並將遞迴計數器加1。
互斥器和關鍵**區的功能是非常相似的,只是乙個是使用者物件,乙個是核心物件
示例:1.使用c++11的mutex的lock和unlock方法
// threadtest.cpp : 定義控制台應用程式的入口點。
//#include "stdafx.h"
// 使用互斥量
#include #include #include #include #include using namespace std;
int g_tickets = 100;
std::mutex g_lock;
unsigned int __stdcall fun1(lpvoid lpparamter)
else
g_lock.unlock();
sleep(1);
} return 0;
}unsigned int __stdcall fun2(lpvoid lpparamter)
else
g_lock.unlock();
sleep(1);
} return 0;
}unsigned int __stdcall fun3(lpvoid lpparamter)
else
g_lock.unlock();
sleep(1);
} return 0;
}int main()
; hthread[0] = (handle)_beginthreadex(nullptr, 0, fun1, nullptr, 0, nullptr);
hthread[1] = (handle)_beginthreadex(nullptr, 0, fun2, nullptr, 0, nullptr);
hthread[2] = (handle)_beginthreadex(nullptr, 0, fun3, nullptr, 0, nullptr);
getchar();
for (int i = 0; i < 3; i++)
closehandle(hthread[i]);
return 0;
}
執行結果:
這個程式有個問題就是,mutex在lock之後,遇到異常,則無法正常unlock,造成死鎖。
示例2 使用std::lock_guard,
原理猜測,在定義lock_guard時,在建構函式裡執行mutex.lock,在析構函式裡執行mutex.unlock,這樣就算出現異常,lock_guard是區域性變數,就會自動釋放記憶體,對應的mutex也就釋放了。
// threadtest.cpp : 定義控制台應用程式的入口點。
//#include "stdafx.h"
// 使用互斥量
#include #include #include #include #include using namespace std;
int g_tickets = 100;
std::mutex g_lock;
unsigned int __stdcall fun1(lpvoid lpparamter)
else
}return 0;
}unsigned int __stdcall fun2(lpvoid lpparamter)
else
}return 0;
}unsigned int __stdcall fun3(lpvoid lpparamter)
else
}return 0;
}int main()
; hthread[0] = (handle)_beginthreadex(nullptr, 0, fun1, nullptr, 0, nullptr);
hthread[1] = (handle)_beginthreadex(nullptr, 0, fun2, nullptr, 0, nullptr);
hthread[2] = (handle)_beginthreadex(nullptr, 0, fun3, nullptr, 0, nullptr);
getchar();
for (int i = 0; i < 3; i++)
closehandle(hthread[i]);
return 0;
}
執行結果:
示例3:使用 unique_lock
unique_lock是個類模板,工作中,一般lock_guard(推薦使用);lock_guard取代了mutex的lock()和unlock();
unique_lock比lock_guard靈活很多,效率上差一點,記憶體占用多一點。
// threadtest.cpp : 定義控制台應用程式的入口點。
//#include "stdafx.h"
// 使用互斥量
#include #include #include #include #include using namespace std;
int g_tickets = 100;
std::mutex mymutex;
unsigned int __stdcall fun1(lpvoid lpparamter)
else
}else
} return 0;
}unsigned int __stdcall fun2(lpvoid lpparamter)
else
}else
}return 0;
}unsigned int __stdcall fun3(lpvoid lpparamter)
else
}else
}return 0;
}int main()
; hthread[0] = (handle)_beginthreadex(nullptr, 0, fun1, nullptr, 0, nullptr);
hthread[1] = (handle)_beginthreadex(nullptr, 0, fun2, nullptr, 0, nullptr);
hthread[2] = (handle)_beginthreadex(nullptr, 0, fun3, nullptr, 0, nullptr);
getchar();
for (int i = 0; i < 3; i++)
closehandle(hthread[i]);
return 0;
}
執行結果:
分析:try_lock()函式嘗試給互斥量加鎖,如果拿不到鎖,返回false,如果拿到了鎖,返回true,這個函式是不阻塞的;
std::defer_lock構造unique_lock時,不給mutex上鎖。
C 11多執行緒使用互斥變數
在學習作業系統的時候,有學過互斥變數,也就是用來保護原子數在同一時刻只能被乙個執行緒進行訪問和修改。c 中通過例項化 std mutex 建立互斥量,通過呼叫成員函式lock 進行上鎖,unlock 進行解鎖。不過,不推薦實踐中直接去呼叫成員函式,因為呼叫成員函式就意味著,必須記住在每個函式出口都要...
C11編輯器公升級和C11標準使用
c11中的一些特性需要對應的編譯器才能支援。而有些系統預設的編譯器並不支援c11,所以需要4.8及其以上的版本。以下採用c11才支援的std unordered set來進行測試。include include include include include using namespace std ...
C 11的function函式物件
c 中的函式種類很多 但這些函式可能共享一種呼叫方式。呼叫形式指明了呼叫返回的型別以及傳遞給呼叫的實參型別。比如 int int,int std function是乙個通用的多態函式包裝器,可以呼叫普通函式 lambda函式 仿函式 bind物件 類的成員函式和指向資料成員的指標,function定...