一,互斥锁
互斥锁(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相比,允许递归加锁。