- 互斥鎖(Mutex)
原理:
互斥鎖用於保護共享資源,確保在同一時刻只有一個執行緒能夠訪問被保護的資源。當一個執行緒想要訪問共享資源時,它首先嚐試獲取互斥鎖。如果鎖已經被其他執行緒持有,那麼該執行緒會被阻塞,直到鎖被釋放。一旦獲取到鎖,執行緒就可以安全地訪問共享資源,訪問結束後再釋放鎖,以便其他執行緒能夠獲取鎖並訪問資源。
示例程式碼:
cpp
複製
#include <iostream>
#include <thread>
#include <mutex>
// 定義一個互斥鎖
std::mutex mutex_f;
// 共享資源,這裡是一個簡單的整數變數
int shared_resource = 0;
// 執行緒函式,用於對共享資源進行操作
void increment_resource() {
// 獲取互斥鎖
std::lock_guard<std::mutex> guard(mutex_f);
// 對共享資源進行操作
shared_resource++;
// 釋放互斥鎖(由lock_guard的解構函式自動完成)
}
int main() {
// 建立兩個執行緒
std::thread t1(increment_resource);
std::thread t2(increment_resource);
// 等待執行緒完成
t1.join();
t2.join();
// 輸出共享資源的值
std::cout << "Shared resource value: " << shared_resource << std::endl;
return 0;
}
在上述示例中,透過std::lock_guard來自動管理互斥鎖的獲取和釋放,確保在increment_resource函式中對共享資源shared_resource的操作是執行緒安全的。
2. 條件變數(Condition Variable)
原理:
條件變數通常與互斥鎖一起使用,用於讓一個執行緒等待某個特定條件的滿足。執行緒首先獲取互斥鎖,然後檢查條件是否滿足。如果條件不滿足,執行緒會釋放互斥鎖並進入等待狀態,直到被其他執行緒透過通知機制喚醒。被喚醒後,執行緒會再次獲取互斥鎖並重新檢查條件是否滿足,只有當條件滿足時才會繼續執行後續操作。
示例程式碼:
cpp
複製
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
// 定義互斥鎖和條件變數
std::mutex mutex_g;
std::condition_variable condition_g;
// 共享資源,這裡是一個簡單的整數變數
int shared_resource_g = 0;
// 用於標識條件是否滿足的標誌
bool condition_met = false;
// 執行緒函式,用於增加共享資源的值並在滿足條件時通知其他執行緒
void increment_and_notify() {
// 獲取互斥鎖
std::lock_guard<std::mutex> guard(mutex_g);
// 對共享資源進行操作
shared_resource_g++;
// 當共享資源的值達到一定程度時,設定條件滿足標誌並通知其他執行緒
if (shared_resource_g >= 5) {
condition_met = true;
condition_g.notify_all();
}
}
// 執行緒函式,用於等待條件滿足
void wait_for_condition() {
// 獲取互斥鎖
std::unique_lock<std::mutex> lock(mutex_g);
// 等待條件滿足,當條件不滿足時釋放互斥鎖並進入等待狀態
condition_g.wait(lock, []{ return condition_met; });
// 條件滿足後,輸出相關資訊
std::cout << "Condition met, shared resource value: " << shared_resource_g << std::endl;
}
int main() {
// 建立兩個執行緒
std::thread t1(increment_and_notify);
std::thread t2(wait_for_condition);
// 等待執行緒完成
t1.join();
t2.join();
return 0;
}
在上述示例中,increment_and_notify執行緒負責增加共享資源的值,並在滿足特定條件(shared_resource_g >= 5)時通知其他執行緒。wait_for_condition執行緒則透過條件變數等待條件滿足,在條件滿足後輸出相關資訊。
3. 訊號量(Semaphore)
原理:
訊號量是一種用於控制對共享資源訪問的計數器。它有一個初始值,表示可用資源的數量。當一個執行緒想要訪問共享資源時,它會先嚐試獲取訊號量。如果訊號量的值大於 0,執行緒就可以獲取訊號量(即將訊號量的值減 1)並訪問共享資源。訪問結束後,執行緒會釋放訊號量(即將訊號量的值加 1),以便其他執行緒能夠獲取訊號量並訪問資源。如果訊號量的值為 0,執行緒會被阻塞,直到有其他執行緒釋放訊號量。
示例程式碼:
cpp
複製
#include <iostream>
#include <thread>
#include <semaphore.h>
// 定義一個訊號量,並設定初始值為3,表示有3個可用資源
sem_t semaphore_h;
// 共享資源,這裡簡單地用一個整數變數表示
int shared_resource_h = 0;
// 執行緒函式,用於獲取訊號量、訪問共享資源並釋放訊號量
void access_shared_resource() {
// 獲取訊號量
sem_wait(&semaphore_h);
// 對共享資源進行操作
shared_resource_h++;
// 釋放訊號量
sem_post(&semaphore_h);
// 輸出相關資訊
std::cout << "Accessed shared resource, current value: " << shared_resource_h << std::endl;
}
int main() {
// 初始化訊號量
sem_init(&semaphore_h, 0, 3);
// 建立三個執行緒
std::thread t1(access_shared_resource);
std::thread t2(access_shared_resource);
std::thread t3(access_shared_resource);
// 等待執行緒完成
t1.join();
t2.join();
t3.join();
// 銷燬訊號量
sem_destroy(&semaphore_h);
return 0;
}
在上述示例中,透過sem_wait獲取訊號量,sem_post釋放訊號量,實現了對共享資源shared_resource_h的執行緒安全訪問。
4. 讀寫鎖(Read-Write Lock)
原理:
讀寫鎖用於區分對共享資源的讀操作和寫操作。多個執行緒可以同時進行讀操作,因為讀操作不會改變共享資源的狀態。但是,當有一個執行緒進行寫操作時,其他執行緒無論是讀還是寫都不能同時進行,必須等待寫操作完成。讀寫鎖透過維護讀鎖和寫鎖的狀態來實現這種區分。
示例程式碼:
cpp
複製
#include <iostream>
#include <thread>
#include <shared_mutex>
// 定義一個讀寫鎖
std::shared_mutex read_write_lock_i;
// 共享資源,這裡是一個簡單的整數變數
int shared_resource_i = 0;
// 執行緒函式,用於進行讀操作
void read_shared_resource() {
// 獲取讀鎖
std::shared_lock<std::shared_mutex> read_lock(read_write_lock_i);
// 對共享資源進行讀操作
std::cout << "Read shared resource value: " << shared_resource_i << std::endl;
// 釋放讀鎖(由shared_lock的解構函式自動完成)
}
// 執行緒函式,用於進行寫操作
void write_shared_resource() {
// 獲取寫鎖
std::unique_lock<std::shared_mutex> write_lock(read_write_lock_i);
// 對共享資源進行寫操作
shared_resource_i++;
// 釋放寫鎖(由unique_lock的解構函式自動完成)
}
int main() {
// 建立三個執行緒進行讀操作,一個執行緒進行寫操作
std::thread t1(read_shared_resource);
std::thread t2(read_shared_resource);
std::thread t3(read_shared_resource);
std::thread t4(write_shared_resource);
// 等待執行緒完成
t1.join();
t2.join();
t3.join();
t4.join();
return 0;
}
在上述示例中,透過std::shared_lock獲取讀鎖進行讀操作,透過std::unique_lock獲取寫鎖進行寫操作,實現了對共享資源shared_resource_i的讀寫操作的執行緒安全管理。
5. 原子型別(Atomic Types)
原理:
原子型別是 C++11 及以後引入的一種資料型別,它允許對其進行原子操作,即這些操作在多執行緒環境下是不可分割的,要麼完整執行,要麼不執行,不存在中間狀態被其他執行緒看到的情況。常見的原子型別有std::atomic
示例程式碼:
cpp
複製
#include <iostream>
#include <thread>
#include <atomic>
// 定義一個原子型別的整數變數
std::atomic<int> atomic_shared_resource_j(0);
// 執行緒函式,用於對原子型別的共享資源進行操作
void increment_atomic_resource() {
// 對原子型別的共享資源進行操作
atomic_shared_resource_j++;
// 輸出相關資訊
std::cout << "Atomic shared resource value: " << atomic_shared_resource_j.load() << std::endl;
}
int main() {
// 建立兩個執行緒
std::thread t1(increment_atomic_resource);
std::thread t2(increment_atomic_resource);
// 等待執行緒完成
t1.join();
t2.join();
return 0;
}
在上述示例中,透過使用std::atomic