標籤:不同的 second 語義 post 處理 names 變化 grant resource
考慮互斥量的使用,最基本的代碼是:
1 #include <iostream> 2 #include <thread> 3 #include <mutex> 4 5 std::mutex g_my_mutex; 6 7 std::lock_guard<std::mutex> make_lock() { 8 return std::lock_guard<std::mutex>(g_my_mutex); 9 }10 11 void workOnResource1() {12 13 for (int i = 0; i < 10000; ++i)14 {15 std::lock_guard<std::mutex> lk(g_my_mutex);16 --gi;17 }18 }19 20 void workOnResource2() {21 22 for (int i = 0; i < 10000; ++i)23 {24 auto lk = make_lock();25 ++gi;26 }27 }28 29 int main() {30 31 std::thread t1(workOnResource1);32 std::thread t2(workOnResource2);33 34 t1.join();35 t2.join();36 37 std::cout << "gi=" <<gi;38 }
這在很多例子裡都常見。等等,為什麼第8行編譯不過去?那是因為您沒有在C++17下編譯。std::lock_guard是禁止拷貝和移動的。C++17 granteed copy ellision允許第8行編譯通過。
比較一下,第24行和第15行,哪個更簡潔一些呢?
std::lock_guard還可以這樣用:
void workOnResource1() { for (int i = 0; i < 10000; ++i) { g_my_mutex.lock(); std::lock_guard<std::mutex> lk(g_my_mutex, std::adopt_lock); --gi; }}
意思就是,當lk物件建構時,不去調用mutex::lock()。因為之前自己所持有的鎖已經lock了一次了(g_my_mutex.lock())。adopt就是這個意思的表達,英文的含義是收養。
當lk析構時,對g_my_mutex調用mutex::unlock,這一點沒有變化。
現在考慮unique_lock的用法:用於更複雜的互斥量操作上,例如:有逾時時間的加鎖。
#include <iostream>#include <thread>#include <mutex> // std::mutex, std::lock_guard #include <chrono>using Ms = std::chrono::milliseconds;using namespace std;int gi = 0;std::timed_mutex g_my_mutex;std::lock_guard<std::timed_mutex> make_lock() { return std::lock_guard<std::timed_mutex>(g_my_mutex); //絕不能分行寫}void workOnResource1() { for (int i = 0; i < 10000; ++i) { auto lk = make_lock(); ++gi; }}std::unique_lock<std::timed_mutex> make_lock2() { std::unique_lock<std::timed_mutex> lk(g_my_mutex, std::defer_lock); return lk; //故意分行寫}void workOnResource2() { for (int i = 0; i < 10000; ++i) { auto lk = make_lock2(); while(lk.try_lock_for(Ms(100))==false){ std::cout << "lock fail. reason timeout. now retry..."; } --gi; }}int main() { std::thread t1(workOnResource1); std::thread t2(workOnResource2); t1.join(); t2.join(); std::cout << "gi=" <<gi;}
unique_lock支援move語義,這樣它就能飛出{}之外了。像極了std::unique_ptr。同樣的,它也是RAII的,當析構時,調用mutex::unlock().
std::defer_lock是個全域變數,類型是std::defer_lock_t。顯然,它用於函數的重載解析時,選不同的函數執行的。defer_lock的意思是,暫時不對g_my_mutex調用任何加鎖動作。
為了證明,unique_lock是可以move的,可以這樣:
std::unique_lock<std::timed_mutex> lk(g_my_mutex, std::defer_lock);std::unique_lock<std::timed_mutex> lk2(std::move(lk));lk2.lock();
scoped_lock是C++17新引進的,在處理多個互斥量時,特別簡單:
參考:http://en.cppreference.com/w/cpp/thread/scoped_lock
C++ scoped_lock,unique_lock,lock_guard