示例詳解C++中的各種鎖
更新時(shí)間:2024年11月06日 08:53:45 作者:Arthurian
C++中常見的鎖包括互斥鎖、遞歸互斥鎖、讀寫鎖、定時(shí)互斥鎖、遞歸定時(shí)互斥鎖、自旋鎖和條件變量,互斥鎖用于防止多線程同時(shí)訪問共享資源,遞歸互斥鎖允許同一線程多次獲取鎖,讀寫鎖區(qū)分讀寫操作,提高并發(fā)性
在多線程開發(fā)中,經(jīng)常會(huì)遇到數(shù)據(jù)同步,很多情況下用鎖都是一個(gè)很好的選擇。C++中常用的鎖主要有下面幾種:
互斥鎖(std::mutex)
- 這是最基本的一種鎖。它用于保護(hù)共享資源,在任意時(shí)刻,最多只有一個(gè)線程可以獲取該鎖,從而訪問被保護(hù)的資源。當(dāng)一個(gè)線程獲取了互斥鎖后,其他試圖獲取該鎖的線程會(huì)被阻塞,直到持有鎖的線程釋放它。
- 例如,在一個(gè)多線程程序中,如果多個(gè)線程需要訪問和修改同一個(gè)全局變量,就可以使用互斥鎖來確保在同一時(shí)間只有一個(gè)線程能夠進(jìn)行修改操作,避免數(shù)據(jù)競(jìng)爭(zhēng)導(dǎo)致的錯(cuò)誤結(jié)果。
#include <iostream> #include <mutex> #include <thread> std::mutex m; int counter = 0; void increment() { m.lock(); counter++; std::cout << "Counter value in thread " << std::this_thread::get_id() << " is " << counter << std::endl; m.unlock(); } int main() { std::thread t1(increment); std::thread t2(increment); t1.join(); t2.join(); return 0; }
遞歸互斥鎖(std::recursive_mutex)
- 遞歸互斥鎖允許同一個(gè)線程多次獲取該鎖。它內(nèi)部會(huì)記錄鎖的獲取次數(shù),每獲取一次,計(jì)數(shù)加 1,每次釋放鎖時(shí),計(jì)數(shù)減 1,當(dāng)計(jì)數(shù)為 0 時(shí),鎖才真正被釋放,可供其他線程獲取。
- 假設(shè)在一個(gè)復(fù)雜的函數(shù)調(diào)用鏈中,函數(shù) A 調(diào)用函數(shù) B,函數(shù) B 又調(diào)用函數(shù) A,并且這些函數(shù)都需要訪問同一個(gè)受保護(hù)的資源。如果使用普通互斥鎖,就會(huì)出現(xiàn)死鎖,而遞歸互斥鎖就可以避免這種情況,因?yàn)樗试S同一線程多次獲取鎖。
#include <iostream> #include <mutex> #include <thread> std::recursive_mutex rm; void recursiveFunction(int count) { rm.lock(); if (count > 0) { std::cout << "Recursive call with count = " << count << std::endl; recursiveFunction(count - 1); } rm.unlock(); } int main() { std::thread t(recursiveFunction, 3); t.join(); return 0; }
讀寫鎖(std::shared_mutex) C++17開始才有
- 讀寫鎖主要用于區(qū)分對(duì)共享資源的讀操作和寫操作。它有兩種獲取模式:共享模式(讀模式)和獨(dú)占模式(寫模式)。
- 多個(gè)線程可以同時(shí)以共享模式獲取讀寫鎖,這意味著它們可以同時(shí)讀取共享資源,而不會(huì)相互干擾。但是,當(dāng)一個(gè)線程要以獨(dú)占模式獲取讀寫鎖(進(jìn)行寫操作)時(shí),其他線程(無論是讀操作還是寫操作)都不能獲取該鎖,直到寫操作完成并釋放鎖。這種機(jī)制在有大量讀操作和少量寫操作的場(chǎng)景下,可以提高程序的并發(fā)性能。例如,在一個(gè)緩存系統(tǒng)中,多個(gè)線程可能經(jīng)常讀取緩存中的數(shù)據(jù),只有在緩存數(shù)據(jù)需要更新時(shí)才會(huì)進(jìn)行寫操作,使用讀寫鎖可以很好地處理這種情況。
#include <iostream> #include <shared_mutex> #include <thread> #include <vector> std::shared_mutex smtx; int shared_data = 0; void read_data() { std::shared_lock<std::shared_mutex> lock(smtx); std::cout << "Read data: " << shared_data << std::endl; } void write_data(int new_value) { std::unique_lock<std::shared_mutex> lock(smtx); shared_data = new_value; std::cout << "Wrote data: " << shared_data << std::endl; } int main() { std::vector<std::thread> read_threads; for (int i = 0; i < 5; i++) { read_threads.push_back(std::thread(read_data)); } std::thread write_thread(write_data, 10); for (auto& t : read_threads) { t.join(); } write_thread.join(); return 0; }
定時(shí)互斥鎖(std::timed_mutex)
- 定時(shí)互斥鎖是
std::mutex
的擴(kuò)展。除了具備std::mutex
的基本功能外,它還允許線程在嘗試獲取鎖時(shí)設(shè)置一個(gè)超時(shí)時(shí)間。 - 如果在規(guī)定的超時(shí)時(shí)間內(nèi)無法獲取鎖,線程不會(huì)一直等待,而是可以執(zhí)行其他操作或者返回錯(cuò)誤信息。這在一些對(duì)時(shí)間敏感的場(chǎng)景中非常有用,比如在一個(gè)實(shí)時(shí)系統(tǒng)中,線程不能因?yàn)榈却粋€(gè)鎖而無限期地阻塞,需要在一定時(shí)間后放棄獲取并進(jìn)行其他處理。
#include <iostream> #include <chrono> #include <thread> #include <mutex> std::timed_mutex tm; void tryLockFunction() { if (tm.try_lock_for(std::chrono::seconds(1))) { std::cout << "Acquired lock" << std::endl; std::this_thread::sleep_for(std::chrono::seconds(2)); tm.unlock(); } else { std::cout << "Could not acquire lock in time" << std::endl; } } int main() { std::thread t1(tryLockFunction); std::thread t2(tryLockFunction); t1.join(); t2.join(); return 0; }
遞歸定時(shí)互斥鎖(std::recursive_timed_mutex)
- 這是結(jié)合了遞歸互斥鎖和定時(shí)互斥鎖特點(diǎn)的一種鎖。它允許同一線程多次獲取鎖,并且在獲取鎖時(shí)可以設(shè)置超時(shí)時(shí)間。
- 當(dāng)一個(gè)線程多次獲取這種鎖后,需要釋放相同次數(shù)的鎖,鎖才會(huì)真正被釋放,并且在獲取鎖的過程中,如果在超時(shí)時(shí)間內(nèi)無法獲取,線程可以采取相應(yīng)的措施。
#include <iostream> #include <chrono> #include <thread> #include <mutex> std::recursive_timed_mutex rtm; void recursiveTryLockFunction(int count) { if (rtm.try_lock_for(std::chrono::seconds(1))) { std::cout << "Recursive acquired lock, count = " << count << std::endl; if (count > 0) { recursiveTryLockFunction(count - 1); } rtm.unlock(); } else { std::cout << "Could not recursively acquire lock in time" << std::endl; } } int main() { std::thread t(recursiveTryLockFunction, 3); t.join(); return 0; }
自旋鎖(通常用std::atomic_flag實(shí)現(xiàn))
- 自旋鎖是一種忙等待的鎖機(jī)制。當(dāng)一個(gè)線程嘗試獲取自旋鎖而鎖已經(jīng)被占用時(shí),這個(gè)線程不會(huì)進(jìn)入阻塞狀態(tài),而是會(huì)不斷地檢查(“自旋”)鎖是否已經(jīng)被釋放。
- 自旋鎖在等待時(shí)間較短的情況下可能會(huì)有比較好的性能表現(xiàn),因?yàn)樗苊饬司€程切換的開銷。但是,如果等待時(shí)間過長(zhǎng),由于線程一直在占用 CPU 資源進(jìn)行檢查,會(huì)導(dǎo)致 CPU 資源的浪費(fèi)。一般在底層代碼或者對(duì)性能要求極高、等待時(shí)間預(yù)計(jì)很短的場(chǎng)景下使用。
#include <iostream> #include <atomic> #include <thread> std::atomic_flag spinLock = ATOMIC_FLAG_INIT; void criticalSection() { while (spinLock.test_and_set()) { // 自旋等待 } std::cout << "Entered critical section" << std::endl; // 臨界區(qū)操作 spinLock.clear(); } int main() { std::thread t1(criticalSection); std::thread t2(criticalSection); t1.join(); t2.join(); return 0; }
條件變量(std::condition_variable)配合互斥鎖用于同步(嚴(yán)格來說條件變量不是鎖,但常一起用于線程同步場(chǎng)景)
- 條件變量本身不是一種鎖,但它通常和互斥鎖一起使用,用于實(shí)現(xiàn)線程間的同步。它可以讓一個(gè)線程等待某個(gè)條件滿足后再繼續(xù)執(zhí)行。
- 例如,一個(gè)生產(chǎn)者 - 消費(fèi)者模型中,消費(fèi)者線程在緩沖區(qū)為空時(shí)可以使用條件變量等待,直到生產(chǎn)者線程生產(chǎn)出產(chǎn)品并通知消費(fèi)者線程,這個(gè)過程中互斥鎖用于保護(hù)緩沖區(qū)這個(gè)共享資源,條件變量用于實(shí)現(xiàn)線程間的通信和同步。
#include <iostream> #include <thread> #include <mutex> #include <condition_variable> #include <queue> std::mutex mtx; std::condition_variable cv; std::queue<int> buffer; const int bufferSize = 5; void producer() { for (int i = 0; i < 10; ++i) { std::unique_lock<std::mutex> lock(mtx); while (buffer.size() == bufferSize) { cv.wait(lock); } buffer.push(i); std::cout << "Produced: " << i << std::endl; cv.notify_all(); } } void consumer() { for (int i = 0; i < 10; ++i) { std::unique_lock<std::mutex> lock(mtx); while (buffer.empty()) { cv.wait(lock); } int data = buffer.front(); buffer.pop(); std::cout << "Consumed: " << data << std::endl; cv.notify_all(); } } int main() { std::thread producerThread(producer); std::thread consumerThread(consumer); producerThread.join(); consumerThread.join(); return 0; }
到此這篇關(guān)于C++中的各種鎖的文章就介紹到這了,更多相關(guān)C++ 各種鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:
- C++11標(biāo)準(zhǔn)庫 互斥鎖 <mutex> 詳解
- 深入探究C/C++中互斥量(鎖)的實(shí)現(xiàn)原理
- C++11中條件標(biāo)量和互斥鎖應(yīng)用出現(xiàn)死鎖問題
- C++ 互斥鎖原理以及實(shí)際使用介紹
- C++詳細(xì)講解互斥量與lock_guard類模板及死鎖
- C++ std::shared_mutex讀寫鎖的使用
- C++線程中幾類鎖的詳解
- C++11如何實(shí)現(xiàn)無鎖隊(duì)列
- c++多線程之死鎖的發(fā)生的情況解析(包含兩個(gè)歸納,6個(gè)示例)
- 解析C++無鎖隊(duì)列的實(shí)現(xiàn)代碼
相關(guān)文章
C字符串操作函數(shù)實(shí)現(xiàn)方法小結(jié)
這篇文章主要介紹了C字符串操作函數(shù)實(shí)現(xiàn)方法,實(shí)例總結(jié)了C語言字符串操作的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04C語言如何計(jì)算兩個(gè)數(shù)的最小公倍數(shù)
這篇文章主要介紹了C語言如何計(jì)算兩個(gè)數(shù)的最小公倍數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11