示例
僅供參考學習
#include <mutex>
#include <shared_mutex>
#include <thread>
#include <chrono>
#include <iostream>
#include <vector>// ============================================
// 1. std::mutex - 基本互斥鎖
// ============================================
void basic_mutex_example() {std::mutex mtx;int counter = 0;// 1.1 使用 lock_guard - 最簡單的RAII方式{std::lock_guard<std::mutex> lock(mtx);counter++;// 作用域結束時自動解鎖}// 1.2 手動加鎖解鎖(不推薦,容易忘記解鎖)mtx.lock();counter++;mtx.unlock();// 1.3 嘗試加鎖if (mtx.try_lock()) {counter++;mtx.unlock();}
}// ============================================
// 2. std::unique_lock - 靈活控制鎖
// ============================================
void unique_lock_example() {std::mutex mtx;// 2.1 基本使用(類似lock_guard){std::unique_lock<std::mutex> lock(mtx);// 臨界區代碼} // 自動解鎖// 2.2 延遲加鎖{std::unique_lock<std::mutex> lock(mtx, std::defer_lock);// 此時還沒有加鎖// 做一些不需要鎖的工作lock.lock(); // 手動加鎖// 臨界區工作lock.unlock(); // 手動解鎖// 更多不需要鎖的工作lock.lock(); // 再次加鎖// 更多臨界區工作} // 如果持有鎖,會自動解鎖// 2.3 嘗試加鎖{std::unique_lock<std::mutex> lock(mtx, std::try_to_lock);if (lock.owns_lock()) {// 成功獲取鎖std::cout << "獲取鎖成功\n";} else {std::cout << "獲取鎖失敗\n";}}// 2.4 超時加鎖(需要timed_mutex)std::timed_mutex timed_mtx;{std::unique_lock<std::timed_mutex> lock(timed_mtx, std::defer_lock);if (lock.try_lock_for(std::chrono::milliseconds(100))) {std::cout << "在100ms內獲取鎖成功\n";} else {std::cout << "超時,獲取鎖失敗\n";}}// 2.5 移動語義auto create_lock = []() {std::unique_lock<std::mutex> lock(mtx);return lock; // 可以移動返回};std::unique_lock<std::mutex> moved_lock = create_lock();// moved_lock現在持有鎖
}// ============================================
// 3. std::shared_mutex - 讀寫鎖
// ============================================
void shared_mutex_example() {std::shared_mutex rw_mtx;std::string shared_data = "初始數據";// 3.1 讀鎖 - 多個線程可以同時讀auto reader = [&]() {std::shared_lock<std::shared_mutex> read_lock(rw_mtx);std::cout << "讀取: " << shared_data << std::endl;// 可以有多個線程同時執行這里};// 3.2 寫鎖 - 獨占訪問auto writer = [&]() {std::unique_lock<std::shared_mutex> write_lock(rw_mtx);shared_data = "更新后的數據";std::cout << "寫入完成" << std::endl;// 只有一個線程可以執行這里,且會阻塞所有讀者};// 啟動多個讀線程和一個寫線程std::vector<std::thread> threads;for (int i = 0; i < 3; ++i) {threads.emplace_back(reader);}threads.emplace_back(writer);for (auto& t : threads) {t.join();}
}// ============================================
// 4. std::recursive_mutex - 遞歸互斥鎖
// ============================================
void recursive_mutex_example() {std::recursive_mutex rec_mtx;int count = 0;std::function<void(int)> recursive_func = [&](int n) {std::lock_guard<std::recursive_mutex> lock(rec_mtx);count++;std::cout << "遞歸層級: " << n << ", count: " << count << std::endl;if (n > 0) {recursive_func(n - 1); // 同一線程可以多次獲取鎖}};recursive_func(3);
}// ============================================
// 5. std::timed_mutex - 超時互斥鎖
// ============================================
void timed_mutex_example() {std::timed_mutex timed_mtx;// 5.1 嘗試在指定時間內獲取鎖if (timed_mtx.try_lock_for(std::chrono::milliseconds(100))) {std::cout << "在100ms內獲取鎖成功\n";// 臨界區工作timed_mtx.unlock();} else {std::cout << "超時,獲取鎖失敗\n";}// 5.2 嘗試在指定時間點前獲取鎖auto timeout_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(200);if (timed_mtx.try_lock_until(timeout_time)) {std::cout << "在指定時間點前獲取鎖成功\n";timed_mtx.unlock();} else {std::cout << "超時,獲取鎖失敗\n";}
}// ============================================
// 6. 多鎖管理 - 避免死鎖
// ============================================
void multi_lock_example() {std::mutex mtx1, mtx2;// 6.1 std::lock - 同時鎖定多個互斥鎖,避免死鎖{std::lock(mtx1, mtx2); // 原子性地鎖定兩個互斥鎖std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);// 臨界區代碼}// 6.2 std::scoped_lock (C++17) - 更簡單的多鎖管理{std::scoped_lock lock(mtx1, mtx2); // 自動管理多個鎖// 臨界區代碼}
}// ============================================
// 7. 條件變量配合使用
// ============================================
void condition_variable_example() {std::mutex mtx;std::condition_variable cv;bool ready = false;// 等待線程auto waiter = [&]() {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, [&] { return ready; }); // 等待條件滿足std::cout << "條件滿足,繼續執行\n";};// 通知線程auto notifier = [&]() {std::this_thread::sleep_for(std::chrono::milliseconds(100));{std::lock_guard<std::mutex> lock(mtx);ready = true;}cv.notify_one(); // 通知等待的線程};std::thread t1(waiter);std::thread t2(notifier);t1.join();t2.join();
}// ============================================
// 8. 實際應用示例 - 線程安全的計數器
// ============================================
class ThreadSafeCounter {
private:mutable std::mutex mtx_;int count_ = 0;public:void increment() {std::lock_guard<std::mutex> lock(mtx_);++count_;}void decrement() {std::lock_guard<std::mutex> lock(mtx_);--count_;}int get() const {std::lock_guard<std::mutex> lock(mtx_);return count_;}// 復雜操作示例void add_if_positive(int value) {std::unique_lock<std::mutex> lock(mtx_);if (count_ > 0) {count_ += value;}}
};// ============================================
// 9. 性能考慮和最佳實踐
// ============================================
void performance_tips() {std::mutex mtx;// ? 好的做法:盡量縮小臨界區{int temp_result = 0;// 在鎖外做復雜計算for (int i = 0; i < 1000; ++i) {temp_result += i * i;}std::lock_guard<std::mutex> lock(mtx);// 只在必要時持有鎖// shared_data = temp_result;}// ? 不好的做法:在臨界區內做復雜計算{std::lock_guard<std::mutex> lock(mtx);// 不要在鎖內做復雜計算int result = 0;for (int i = 0; i < 1000; ++i) {result += i * i;}// shared_data = result;}
}int main() {std::cout << "=== C++ 互斥鎖使用示例 ===" << std::endl;basic_mutex_example();unique_lock_example();shared_mutex_example();recursive_mutex_example();timed_mutex_example();multi_lock_example();condition_variable_example();// 測試線程安全計數器ThreadSafeCounter counter;std::vector<std::thread> threads;for (int i = 0; i < 10; ++i) {threads.emplace_back([&counter]() {for (int j = 0; j < 100; ++j) {counter.increment();}});}for (auto& t : threads) {t.join();}std::cout << "最終計數: " << counter.get() << std::endl;return 0;
}
核心概念總結
1. 互斥鎖類型
- std::mutex: 基本互斥鎖,最常用
- std::recursive_mutex: 遞歸鎖,同一線程可多次獲取
- std::timed_mutex: 支持超時的互斥鎖
- std::shared_mutex: 讀寫鎖,支持多讀者單寫者
2. 鎖管理器
- std::lock_guard: 最簡單的RAII鎖,構造時加鎖,析構時解鎖
- std::unique_lock: 靈活的鎖管理器,支持延遲加鎖、手動控制等
- std::shared_lock: 用于共享鎖(讀鎖)
- std::scoped_lock: C++17引入,用于管理多個鎖
3. 鎖標簽
- std::defer_lock: 延遲加鎖
- std::try_to_lock: 嘗試加鎖
- std::adopt_lock: 接管已經持有的鎖
4. 最佳實踐
- 優先使用 lock_guard - 簡單場景的首選
- 需要靈活控制時使用 unique_lock - 如需要手動解鎖/加鎖
- 讀多寫少用 shared_mutex - 提高并發性能
- 盡量縮小臨界區 - 減少鎖持有時間
- 避免死鎖 - 使用 std::lock 或 std::scoped_lock 管理多個鎖
- 配合條件變量使用 unique_lock - 因為條件變量需要能夠釋放鎖
5. 選擇建議
- 簡單保護:std::mutex + std::lock_guard
- 需要靈活控制:std::mutex + std::unique_lock
- 讀多寫少:std::shared_mutex + std::shared_lock/std::unique_lock
- 遞歸調用:std::recursive_mutex
- 超時需求:std::timed_mutex
這些工具組合使用可以解決絕大多數多線程同步問題。