轉載:https://blog.csdn.net/faihung/article/details/88411839
https://blog.csdn.net/XindaBlack/article/details/105915806
簡介:std::mutex:互斥量,C++11中與mutex相關的類(包括鎖類型)和函數都聲明在<mutex>頭文件中。(C++官網)
讀寫鎖:后續補充
自旋鎖:后續補充
<mutex> 頭文件介紹
mutex系列類(四種):
- std::mutex:最基本的mutex類
- std::recursive_mutex:遞歸mutex類
- std::timed_mutex:定時mutex類
- std::recursive_timed_mutex:遞歸定時mutex類
lock類(兩種):
- std::lock_guard:與mutex RAII 相關,方便線程對互斥量上鎖
- std::unique_lock:與mutex RAII相關,方便線程對互斥量上鎖,但提供了更好的上鎖和解鎖控制
其他類型:
- std::once_flag
- std::adopt_lock_t
- std::defer_lock_t
- std::try_to_lock_t
函數:
- std::try_lock:嘗試同時對多個互斥量上鎖
- std::lock:可以同時對多個互斥量上鎖
- std::call_once:如果多個線程需要同時調用某個函數,call_once可以保證多個線程對該函數只調用一次
std::mutex介紹
std::mutex是C++11中最基本的互斥量,std::mutex對象提供了獨占所有權的特性——既不支持遞歸地對std::mutex上鎖,而std::recursive_lock可以遞歸地對互斥量對象上鎖。
std::mutex的成員函數
- 構造函數,std::mutex不允許拷貝構造函數,也不允許move拷貝,最初產生的mutex對象是處於unlocked狀態的。
- lock(),調用線程將鎖住該互斥量。線程調用該函數會發生下面3中情況。(1)如果該互斥量當前沒有被鎖住,則調用線程將該互斥量鎖住,知道調用unlock之前,該線程會一直擁有該鎖。(2)如果當前互斥量被其他線程鎖住,則當前的調用線程被阻塞住。(3)如果當前互斥量被當前調用線程鎖住,則會產生死鎖。(第三條應該是遞歸鎖要解決的問題)
- unlock(),解鎖,釋放對互斥量的所有權。
- try_lock(),嘗試鎖住互斥量,如果互斥量被其他線程占有,則當前線程也不會阻塞。線程調用該函數也會出現下面3中情況。(1)如果當前互斥量沒有被其他線程占有,則該線程鎖住互斥量,直到該線程調用unlock釋放互斥量。(3)如果當前互斥量被當前調用線程鎖住,則會產生死鎖。
注意:在編譯的時候可能會報 underfined reference to ‘pthread_create’錯誤,這個在編譯選項中加 -g -lpthread 既可。原因
具體編譯命令:
g++ -std=c++11 lock.cpp -g -lpthread
case 1:mutex
#include <iostream> #include <thread> #include <mutex> using namespace std; volatile int counter(0); mutex mtx; void attempt_10k_increases() { for (int i = 0; i < 10000; ++i) { if (mtx.try_lock()) { ++counter; mtx.unlock(); } } } int main(int argc, const char* argv[]) { thread threads[10]; for (int i=0; i < 10; ++i) { threads[i] = thread(attempt_10k_increases); } for (auto& th : threads) { th.join(); } cout << counter << " successful increases of the counter." << endl; return 0; }
std::recursive_mutex介紹
std::recursive_mutex與std::mutex一樣,也是一種可以被上鎖的對象,但是和std::mutex不同的是,std::recursive_mutex允許同一個線程對互斥量多次上鎖(即遞歸上鎖),來獲取對互斥量對象的多層所有權,std::recursive_mutex釋放互斥量時需要調用與該鎖層次深度相同次數的unlock(),可理解為lock()次數 和 unlock()次數相同,除此之外,std::recursive_mutex的特性和std::mutex大致相同。
std::timed_mutex 介紹
std::timed_mutex 比 std::mutex多了兩個成員函數,try_lock_for(), try_lock_until()。
try_lock_for函數接受一個時間范圍,表示在這一段時間范圍之內線程如果沒有獲得鎖則被阻塞住(與std::mutex的try_lock不同, try_lock如果被調用時沒有獲得鎖則直接返回false),如果在此期間其他線程釋放了鎖,則該線程可以獲得互斥量的鎖,如果超時(即在指定時間內還是沒有獲得鎖),則返回false。
try_lock_until函數則接受一個時間點作為參數,在指定時間點未到來之前線程如果沒有獲得鎖則被阻塞住,如果在此期間其他線程釋放了鎖,則該線程獲得互斥量的鎖,如果超時(即在指定時間內還沒有獲得鎖),則返回false。
case 2 :timed_mutex
#include <iostream> #include <chrono> #include <thread> #include <mutex> using namespace std; timed_mutex mtx; void fireworks() { while (!mtx.try_lock_for(chrono::milliseconds(200))) { cout << "-" ; } this_thread::sleep_for(chrono::milliseconds(1000)); cout << "*" << endl; mtx.unlock(); } int main() { thread threads[10]; for (int i = 0; i <10; ++i) { threads[i] = thread(fireworks); } for (auto &th : threads) th.join(); return 0;
std::recursive_timed_mutex 介紹
和std::recursive_mutex 與 std::mutex 的關系一樣,可以通過std::timed_mutex推到。
std::lock_guard介紹
與mutex RAI相關,方便線程對互斥量上鎖。
case 3:lock_guard
#include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex, std::lock_guard #include <stdexcept> // std::logic_error std::mutex mtx; void print_even (int x) { if (x%2==0) std::cout << x << " is even\n"; else throw (std::logic_error("not even")); } void print_thread_id (int id) { try { // using a local lock_guard to lock mtx guarantees unlocking on destruction / exception: std::lock_guard<std::mutex> lck (mtx); print_even(id); } catch (std::logic_error&) { std::cout << "[exception caught]\n"; } } int main () { std::thread threads[10]; // spawn 10 threads: for (int i=0; i<10; ++i) threads[i] = std::thread(print_thread_id,i+1); for (auto& th : threads) th.join(); return 0;
std::unique_lock介紹
case 4 :unique_lock
#include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex, std::unique_lock std::mutex mtx; // mutex for critical section void print_block (int n, char c) { // critical section (exclusive access to std::cout signaled by lifetime of lck): std::unique_lock<std::mutex> lck (mtx); for (int i=0; i<n; ++i) { std::cout << c; } std::cout << '\n'; } int main () { std::thread th1 (print_block,50,'*'); std::thread th2 (print_block,50,'$'); th1.join(); th2.join(); return 0;
unique_lock和lock_guard的區別:
簡單來說就是:unique_lock支持直接加鎖:unique_lock<mutex> lk(mtx);也支持lock和unlock函數。而lock_guard支持lock_guard<mutex> lk(mtx);