一,互斥鎖
互斥鎖(Mutex,全稱 Mutual Exclusion)是并發編程中用于保護共享資源的核心同步機制。它通過確保同一時間僅有一個線程訪問臨界區(Critical Section),解決多線程環境下的數據競爭和不一致性問題。
二,std::mutex
1,頭文件
#include <mutex>
2,特性
- 不支持拷貝構造和拷貝賦值,只有默認構造
- std::mutex對象不支持移動語義,不支持swap。
- std::mutex是非遞歸鎖,遞歸鎖使用std::recursive_mutex
- unlock()次數過多時,會產生未定義的行為
3,成員函數
函數 | 說明 |
---|---|
| 獲取鎖,鎖被其他線程占用時阻塞當前線程。 |
unlock() | 釋放鎖(必須由鎖的持有線程調用)。 |
try_lock() | 獲取鎖,鎖被占用時返回false,但不阻塞當前線程。鎖未被占用且獲取鎖成功時返回true。 |
4,示例代碼
#include <mutex>
#include <iostream>
#include <thread>static std::mutex tex;
void test01()
{std::lock_guard<std::mutex> locker(tex);std::cout << "A" << std::endl;std::cout << "B" << std::endl;std::cout << "====================" << std::endl;
}void test02()
{tex.lock();std::cout << "A" << std::endl;std::cout << "B" << std::endl;std::cout << "====================" << std::endl;tex.unlock();
}void test03()
{if (tex.try_lock()){std::cout << "A" << std::endl;std::cout << "B" << std::endl;std::cout << "====================" << std::endl;tex.unlock();}
}int main()
{std::mutex tess;for (int i = 0; i < 15; i++){std::thread th(test03);//std::thread th(test02);//std::thread th(test01);th.detach();}system("pause");std::cout << "Hello World!\n";
}
5,源碼說明
根據源碼解釋mutex的特性。
_EXPORT_STD class mutex : public _Mutex_base { // class for mutual exclusion
public:// 只支持無參構造mutex() noexcept = default;// 不支持拷貝構造mutex(const mutex&) = delete;// 不支持拷貝賦值mutex& operator=(const mutex&) = delete;
};
void lock() {if (_Mtx_lock(_Mymtx()) != _Thrd_result::_Success) {// 未定義行為,僅發生在普通互斥鎖上(N4950標準 [thread.mutex.requirements.mutex.general]/6 條款)_STD _Throw_Cpp_error(_RESOURCE_DEADLOCK_WOULD_OCCUR);}if (!_Verify_ownership_levels()) {// only occurs for recursive mutexes (N4950 [thread.mutex.recursive]/3)// POSIX specifies EAGAIN in the corresponding situation:// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_lock.html_STD _Throw_Cpp_error(_RESOURCE_UNAVAILABLE_TRY_AGAIN);}}
下面是部分代碼行逐行說明:
_Mtx_lock(_Mymtx()) != _Thrd_result::_Success
_Mymtx()是獲取當前互斥量底層原生句柄。在Windows平臺上,C++標準庫互斥量(std::mutex)的底層原生句柄是CRITICAL_SECTION對象。這是Windows系統提供的高性能線程同步原語,完全由Windows內核創建和管理。
Windows CRITICAL_SECTION本質上是遞歸的。std::mutex的非遞歸特性是由C++標準庫在上層強制實現的。將底層互斥量句柄_Mymtx()傳遞給_Mtx_lock()函數,_Mtx_lock()函數嘗試鎖定互斥鎖,此時會執行遞歸檢測,如果是遞歸加鎖,會導致鎖定失敗,然后拋出異常:
_STD _Throw_Cpp_error(_RESOURCE_DEADLOCK_WOULD_OCCUR);
_Verify_ownership_levels()會檢查遞歸鎖的嵌套深度是否超限。超限時拋出異常。
三,std::recursive_mutex
與std::mutex相比,recursive_mutex是遞歸鎖。它允許同一線程多次獲取鎖而不會導致異常。
1,特性
- recursive_mutex是遞歸鎖,它可以多次調用lock和try_lock(),每次調用會增加內部的鎖計數
- 多次加鎖之后,必須調用同等次數的unlock(),才能解鎖
- 與std::mutex相同,不支持移動語義,不支持swap
- unlock()次數過多時,會產生未定義的行為
2,成員函數
函數 | 說明 |
---|---|
| 獲取鎖,鎖被其他線程占用時阻塞當前線程。獲取鎖成功時,增加鎖計數。 |
unlock() | 減少鎖計數,鎖計數為0時釋放鎖(必須由鎖的持有線程調用)。 |
try_lock() | 獲取鎖,鎖被占用時返回false,但不阻塞當前線程。鎖未被占用且獲取鎖成功時返回true,同時增加鎖計數。 |
3,示例代碼
static std::recursive_mutex tex;
void test01()
{std::lock_guard<std::recursive_mutex> locker(tex);std::lock_guard<std::recursive_mutex> locker1(tex); // 可多次加鎖std::cout << "A" << std::endl;std::cout << "B" << std::endl;std::cout << "====================" << std::endl;
}void test03()
{if (tex.try_lock()){if (tex.try_lock()){std::cout << "A" << std::endl;if (tex.try_lock()){std::cout << "B" << std::endl;if (tex.try_lock()){tex.lock();std::cout << "====================" << std::endl;}}}tex.unlock(); tex.unlock(); tex.unlock(); tex.unlock(); tex.unlock();}
}
四,std::timed_mutex
std::timed_mutex(定時互斥鎖)是 C++11 標準庫提供的帶有超時功能的互斥量類型,它在 std::mutex 基礎上增加了嘗試獲取鎖直到超時的能力,適用于需要避免無限期阻塞的場景。
1,特性
- std::timed_mutex對象不支持拷貝構造和拷貝賦值
- std::timed_mutex對象不支持移動語義,不支持swap
- std::timed_mutex是非遞歸鎖
- unlock()次數過多時,會產生未定義的行為
2,成員函數
函數 | 說明 |
---|---|
lock() | 阻塞直到獲得鎖 |
unlock() | 釋放鎖 |
try_lock() | 立即嘗試獲取鎖(非阻塞) |
try_lock_for(rel_time) | 在相對時間段內嘗試獲取鎖(超時返回?false ) |
try_lock_until(abs_time) | 在絕對時間點前嘗試獲取鎖(超時返回?false ) |
3,示例代碼
#include <mutex>
#include <iostream>
#include <thread>static std::timed_mutex timeMutex;void test04()
{if (!timeMutex.try_lock_for(std::chrono::milliseconds(1000))){std::cout << "獲取鎖超時" << std::endl;}else{std::cout << "A" << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 模擬工作timeMutex.unlock();}
}int main()
{std::mutex tess;for (int i = 0; i < 15; i++){std::thread th(test04);th.detach();}system("pause");std::cout << "Hello World!\n";
}
五:std::recursive_timed_mutex
超時遞歸鎖。與timed_mutex相比,允許遞歸加鎖。