目录
1--std::unique_lock的使用
常用成员函数:
① lock(): 加锁;
② unlock(): 解锁;
③ try_lock(): 不阻塞地尝试给互斥量加锁,获取锁时返回true,否则返回false;
扫描二维码关注公众号,回复: 16247881 查看本文章④ release(): 返回所管理 mutex 的对象指针,并释放所有权,即当 std::unique_lock 对象使用 release 时,对象将与 mutex 不再有任何关系;若原来的 mutex 在解除关系前处于 lock() 状态,则std::unique_lock 对象不再负责自动帮 mutex 进行 unlock() 的工作,程序员需负责手动对 mutex 进行unlock() 的操作;
std::unique_lock<std::mutex> guard1(my_mutex1)
std::mutex *ptr = guard1.release();
...
// 需手动解锁
ptr->unlock();
1-1--std::adopt_lock参数
与 std::lock_guard 中的 std::adopt_lock 类似,当 mutex 手动进行 lock() 后,std::unique_lock 可以使用 std::adopt_lock 告知不使用构造函数来自动 lock(),而只进行 unlock() 的操作;
线程使用 std::adopt_lock 时,线程本身必须首先进行 lock() 操作;
// example
my_mutex1.lock();
// my_mutex1 手动进行lock()以后,在使用std::unique_lock应添加std::adopt_lock参数
std::unique_lock<std::mutex> guard1(my_mutex1, std::adopt_lock);
1-2--std::try_to_lock参数
当一个线程使用 std::unique_lock 无法随时获取锁时,可以使用 std::try_to_lock 来尝试获取锁,如果获取成功则执行临界区的内容,如果无法获取锁则可以让线程做其他工作,先不进行临界区的工作;
线程使用 std::try_to_lock 时,线程本身不能首先进行 lock() 操作;
在下面的代码实例中,取数据的线程在获取锁后会休息一段时间,此时发数据的线程无法获取锁,只能等待;
当使用 std::try_to_lock 参数时,发数据的线程会尝试获取锁,如果获取成功了则实行临界区的内容,向消息队列发送数据;如果获取失败,则执行 else 语句的内容,直到获取锁为止;
#include <iostream>
#include <thread>
#include <list>
#include <mutex>
class myClass{
public:
// 收集数据到消息队列
void inMsgRecvQueue(){
for(int i = 0; i < 100; i++){
std::unique_lock<std::mutex> guard1(my_mutex1, std::try_to_lock);
if(guard1.owns_lock()){ // 获取锁,执行临界区
std::cout << "Running inMsgRecvQueue(), insert one value: "
<< i << std::endl;
msgRecvqueue.push_back(i); // 消息队列存储消息
}
else{ // 无法获取锁,执行其他工作
std::cout << "Running inMsgRecvQueue(), do other works" << std::endl;
}
}
}
// 从消息队列取数据
void outMsgRecvQueue(){
for(int i = 0; i < 100; i++){
if(!msgRecvqueue.empty()){
// 获取锁后休息10s
std::unique_lock<std::mutex> guard1(my_mutex1);
std::chrono::microseconds dura(20000); // 10000ms
std::this_thread::sleep_for(dura);
// 取出数据
int command = msgRecvqueue.front();
msgRecvqueue.pop_front();
}
else{
std::cout << "Running outMsgRecvQueue(), "
"the msgRecvqueue is empty" << std::endl;
}
}
}
private:
std::list<int> msgRecvqueue; // 消息队列
std::mutex my_mutex1; // 创建互斥量
};
int main(int argc, char *argv[]){
myClass sample1;
std::thread myInMsgObj(&myClass::inMsgRecvQueue, &sample1); // 收集数据线程
std::thread myOutMsgObj(&myClass::outMsgRecvQueue, &sample1); // 取出数据线程
myInMsgObj.join();
myOutMsgObj.join();
return 0;
}
1-3--std::defer_lock参数
std::unique_lock 使用 std::defer_lock 时,不会对绑定的 mutex 进行 lock(),作用是将mutex 与线程进行绑定,后续根据情况考虑是否手动进行 lock() 操作;
线程使用 std::defer_lock 时,线程本身不能首先进行 lock() 操作;
1-4--互斥量所有权转移
通过 std::move 可以转移 std::unique_lock 对象关于 mutex 的所有权;在下面的代码中,guard2 将拥有 my_mutex1 的所有权,guard1 指向空;
std::unique_lock<std::mutex> guard1(my_mutex1);
std::std::unique_lock<std::mutex> guard2(std::move(guard1));