您好,登錄后才能下訂單哦!
本篇內容主要講解“C++互斥鎖原理及實際使用方法是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“C++互斥鎖原理及實際使用方法是什么”吧!
互斥鎖可以確保在任何時候只有一個線程能夠進入臨界區。當線程需要進入臨界區時,它會嘗試獲取互斥鎖的所有權,如果互斥鎖已經被其他線程占用,那么當前線程就會進入阻塞狀態,直到互斥鎖被釋放為止。簡單說就是一塊區域只能被一個線程執行。
當一個線程獲取到互斥鎖的所有權后,它就可以進入臨界區進行操作,當操作完成后,它需要釋放互斥鎖,讓其他線程有機會進入臨界區。
下面是一個簡單的互斥鎖的示例代碼,它演示了如何使用 std::mutex 類來保護臨界區:
#include <iostream> #include <thread> #include <mutex> // 定義互斥鎖 std::mutex g_mutex; // 臨界區代碼 void critical_section(int thread_id) { // 加鎖 g_mutex.lock(); // 訪問共享資源 std::cout << "Thread " << thread_id << " enter critical section." << std::endl; // 釋放鎖 std::this_thread::sleep_for(std::chrono::seconds(5)); g_mutex.unlock(); } int main() { // 創建兩個線程 std::thread t1(critical_section, 1); std::thread t2(critical_section, 2); // 等待兩個線程執行完成 t1.join(); t2.join(); return 0; }
main中創建兩個線程去訪問資源,但是其中一個需要等待另一個線程5s釋放后才能訪問,形成對資源的鎖定。
上面的例子使用的是std::mutex實現互斥鎖,需要注意這個互斥鎖的聲明需要相對的全局變量,也就是說對于使用鎖的部分它必須是“全局的”。
C++ 中的遞歸互斥量(Recursive Mutex)是一種特殊的互斥量,它可以被同一個線程多次鎖定,而不會發生死鎖。遞歸互斥量的實現原理是,在鎖定時維護一個鎖定計數器,每次解鎖時將計數器減一,只有當計數器為 0 時才會釋放鎖。
以下是遞歸互斥量的示例代碼:
#include <iostream> #include <thread> #include <mutex> std::recursive_mutex mtx; void foo(int n) { mtx.lock(); std::cout << "Thread " << n << " locked the mutex." << std::endl; if (n > 1) { foo(n - 1); } std::cout << "Thread " << n << " unlocked the mutex." << std::endl; mtx.unlock(); } int main() { std::thread t1(foo, 3); std::thread t2(foo, 2); t1.join(); t2.join(); return 0; }
在上面的代碼中,我們定義了一個遞歸函數 foo(),它接受一個整數參數 n,表示當前線程的編號。在函數中,我們首先使用遞歸互斥量 mtx 鎖定當前線程,然后輸出一條帶有線程編號的信息,接著判斷如果 n 大于 1,則遞歸調用 foo() 函數,并將參數減一。最后,我們輸出一條解鎖信息,并將遞歸互斥量解鎖。
在主函數中,我們創建了兩個線程 t1 和 t2,分別調用 foo() 函數,并傳入不同的參數值。由于遞歸互斥量可以被同一個線程多次鎖定,因此在 t1 線程中對 mtx 進行了兩次鎖定,而在 t2 線程中只進行了一次鎖定。
運行結果:
可以看到,遞歸互斥量可以被同一個線程多次鎖定,并且在解鎖時必須對應減少鎖定計數器。這種機制可以避免死鎖的發生,但也需要注意使用時的線程安全問題。
讀寫鎖(Read-Write Lock)是一種特殊的互斥鎖,用于在多線程環境下對共享資源進行讀寫操作。它允許多個線程同時讀取共享資源,但只允許一個線程寫入共享資源。讀寫鎖的使用可以提高并發性能,特別是當讀操作比寫操作頻繁時。
在 C++ 中,讀寫鎖可以通過 std::shared_mutex 類型來實現。下面是一個簡單的示例代碼,演示了如何使用讀寫鎖來保護一個共享的整型變量:
#include <iostream> #include <thread> #include <chrono> #include <shared_mutex> std::shared_mutex rw_lock; // 讀寫鎖 int shared_var = 0; // 共享變量 // 寫線程函數 void writer() { for (int i = 0; i < 10; ++i) { // 獨占寫鎖 std::unique_lock<std::shared_mutex> lock(rw_lock); // 寫共享變量 ++shared_var; std::cout << "Writer thread: write shared_var=" << shared_var << std::endl; // 等待一段時間 std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } // 讀線程函數 void reader(int id) { for (int i = 0; i < 10; ++i) { // 共享讀鎖 std::shared_lock<std::shared_mutex> lock(rw_lock); // 讀共享變量 int value = shared_var; std::cout << "Reader thread " << id << ": read shared_var=" << value << std::endl; // 等待一段時間 std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } int main() { std::thread t1(writer); std::thread t2(reader, 1); std::thread t3(reader, 2); std::thread t4(reader, 3); t1.join(); t2.join(); t3.join(); t4.join(); return 0; }
在上面的代碼中,我們定義了一個共享變量 shared_var 和一個讀寫鎖 rw_lock。寫線程函數 writer() 獨占寫鎖,對 shared_var 進行自增操作,并輸出當前的值。讀線程函數 reader() 共享讀鎖,讀取 shared_var 的值,并輸出當前的值。所有的線程都會等待一段時間,以模擬實際的操作。
在主函數中,我們創建了一個寫線程和三個讀線程。由于讀寫鎖的特性,讀線程可以并發讀取共享變量,而寫線程會獨占寫鎖,只有在寫操作完成之后,讀線程才能再次讀取共享變量。因此,輸出結果中讀線程的順序可能會有所不同,但是寫線程的操作一定是順序執行的。
注意,這里使用 std::unique_lockstd::shared_mutex 類型的對象來獲取獨占寫鎖,使用 std::shared_lockstd::shared_mutex 類型的對象來獲取共享讀鎖。這些鎖對象會在作用域結束時自動解鎖,避免了手動解鎖的問題。
條件變量(Condition Variable)是一種線程間同步機制,用于在某些特定條件下阻塞或喚醒線程。在 C++ 中,條件變量是通過 std::condition_variable 類來實現的。
下面是一個使用條件變量的示例代碼,其中有兩個線程,一個線程不停地生產數據,另一個線程則等待數據,當有數據可用時,將數據進行消費。
#include <iostream> #include <thread> #include <chrono> #include <queue> #include <mutex> #include <condition_variable> std::queue<int> data_queue; // 數據隊列 std::mutex data_mutex; // 互斥鎖 std::condition_variable data_cond; // 條件變量 // 生產數據函數 void producer() { for (int i = 1; i <= 10; ++i) { // 生產數據 std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::unique_lock<std::mutex> lock(data_mutex); data_queue.push(i); std::cout << "Producer thread: produce data " << i << std::endl; // 喚醒消費線程 data_cond.notify_one(); } } // 消費數據函數 void consumer() { while (true) { // 等待數據 std::unique_lock<std::mutex> lock(data_mutex); data_cond.wait(lock, [] { return !data_queue.empty(); }); // 消費數據 int data = data_queue.front(); data_queue.pop(); std::cout << "Consumer thread: consume data " << data << std::endl; // 檢查是否結束 if (data == 10) { break; } } } int main() { std::thread t1(producer); std::thread t2(consumer); t1.join(); t2.join(); return 0; }
在上面的代碼中,我們定義了一個數據隊列 data_queue 和一個互斥鎖 data_mutex,同時定義了一個條件變量 data_cond。生產數據的函數 producer() 不停地往隊列中添加數據,每次添加完數據之后,通過調用 data_cond.notify_one() 喚醒等待的消費線程。消費數據的函數 consumer() 通過調用 data_cond.wait(lock, [] { return !data_queue.empty(); }) 來等待數據,當隊列中有數據時,將數據從隊列中取出并消費,如果取出的數據是最后一個,則退出循環。
在主函數中,我們創建了一個生產線程和一個消費線程。生產線程生產 10 個數據,消費線程從隊列中消費數據,直到消費到最后一個數據為止。
注意,這里使用了 std::unique_lockstd::mutex 類型的對象來獲取互斥鎖,并使用 lambda 表達式 [] { return !data_queue.empty(); } 來判斷條件是否滿足。在調用 wait() 函數時,當前線程會阻塞,直到條件變量被其他線程喚醒或超時。當 wait() 函數返回時,當前線程會重新獲取互斥。
簡單一些的例子:
#include <iostream> #include <thread> #include <chrono> #include <mutex> #include <condition_variable> bool ready = false; // 條件變量 std::mutex data_mutex; // 互斥鎖 std::condition_variable data_cond; // 條件變量 void do_something() { // 模擬工作 std::this_thread::sleep_for(std::chrono::milliseconds(500)); } void waiting_thread() { // 等待條件變量 std::unique_lock<std::mutex> lock(data_mutex); data_cond.wait(lock, [] { return ready; }); // 條件滿足后輸出一句話 std::cout << "Condition satisfied, waiting thread resumes." << std::endl; do_something(); } int main() { std::thread t1(waiting_thread); // 模擬條件滿足后的操作 std::this_thread::sleep_for(std::chrono::milliseconds(1000)); { std::lock_guard<std::mutex> lock(data_mutex); ready = true; data_cond.notify_one(); } t1.join(); return 0; }
在上面的代碼中,我們定義了一個條件變量 ready 和一個互斥鎖 data_mutex,同時定義了一個條件變量 data_cond。等待條件變量的函數 waiting_thread() 首先獲取互斥鎖,然后通過調用 data_cond.wait(lock, [] { return ready; }) 等待條件變量,當 ready 為 true 時,線程會被喚醒,輸出一句話,并模擬一些工作的操作。在主函數中,我們創建了一個等待條件變量的線程 t1,然后模擬條件滿足后的操作,即將 ready 設置為 true,然后通過調用 data_cond.notify_one() 喚醒等待的線程。
到此,相信大家對“C++互斥鎖原理及實際使用方法是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。