c++ std::mutex与std::condition_variable
1. std::mutex
lock()加锁; try_lock()尝试加锁; unlock()解锁;
std::mutex m_mutex; m_mutex.lock();
...
m_mutex.unlock();
2. std::lock_guard
类模板;等同自动锁,直接取代lock()和unlock(); 构造时加锁,析构时解锁;
std::mutex m_mutex;
{std::lock_guard<std::mutex> myLock(m_mutex);...
} //作用域执行完,自动unlock解锁;
3. std::unique_lock
类模板, 比lock_guard灵活,效率比lock_guard差一点,内存占用比lock_guard多一点;所以工作中使用lock_guard就够了;
3.1 unuque_lock的第二参数
std::adopt_lock: 表示互斥量已经被lock()了 (互斥量必须提前lock()否则错误);
std::mutex m_mutex;
{m_mutex.lock();std::unique_lock<std::mutex> myLock(m_mutex, std::adopt_lock);
}
std::defer_lock: 没有给mutex加锁,初始化一个没有加锁的mutex; 故不能提前自己加锁,否则错误;
std::mutex m_mutex;{//之前不能加锁std::unique_lock<std::mutex> myLock(m_mutex, std::defer_lock);myLock.lock();}
std::try_to_lock: 尝试用mutex加锁,加锁失败会立即返回,不阻塞; 前提是不能自己先加锁;
std::mutex m_mutex;
{//之前不能加锁std::unique_lock<std::mutex> myLock(m_mutex, std::try_to_lock);if (myLock.owns_lock()) {std::cout << "get lock suc" << std::endl;}else {std::cout << "get lock failed" << std::endl;}
}
3.2 成员函数
lock(): 加锁;
unlock():解锁;
std::mutex m_mutex;
{std::unique_lock<std::mutex> myLock(m_mutex);...myLock.unlock();myLock.lock();...myLock.unlock(); //可加可不加
}
try_lock():尝试加锁;
owns_lock(): 加锁成功返回true, 加锁失败返回false;
release(): 返回管理的锁对象指针,并将其置空;
//若原来 mutex处于加锁状态,那么接管过来需要我们自己解锁;
std::unique_lock<std::mutex> myLock(m_mutex1);
std::timed_mutex *ptx = myLock.release();//现在你有责任自己解锁了;
ptx->unlock();
4. std::condition_variable
条件变量,用于线程同步; 搭配std::mutex一起使用;
4.1 wait
/* 源码 */
void wait(unique_lock<mutex>& _Lck) { // wait for signal// Nothing to do to comply with LWG-2135 because std::mutex lock/unlock are nothrow_Cnd_wait(_Mycnd(), _Lck.mutex()->_Mymtx());
}template <class _Predicate>
void wait(unique_lock<mutex>& _Lck, _Predicate _Pred) { // wait for signal and test predicatewhile (!_Pred()) {wait(_Lck);}
}
带有_Predicate 的重载函数用于判断条件是否满足;
std::mutex m_mutex;
std::condition_variable m_cond;{std::unique_lock<std::mutex> lock(m_mutex);#if 1/*wait将解锁互斥量,并阻塞到本行, 直到其他某个线程调用notify_one/all唤醒;当被唤醒后,wait()尝试获取互斥量;获取成功即上锁;判断参数2 lambda结果,为false则解锁,阻塞本行;为true,则wait()返回,继续执行下面代码;*/m_cond.wait(lock, [this] {if (条件==true) return true;return false;});...#else//wait将解锁互斥量,并阻塞到本行; 直到其他某个线程调用notify_one/all唤醒;//wait()后从新获取锁; 获取成功直接返回,继续下面流程m_cond.wait(lock);流程走到这里, lock一定是锁着的;#endif
}
4.2 notify
notify_one: 唤醒wait等待的一个线程,只能唤醒一次;
notify_all: 唤醒wait等待的所有线程,广播形式全部通知; 但是只有一个获取锁成功;
//m_cond.notify_one(); //唤醒一个
m_cond.notify_all();//唤醒多个线程