C++并发多线程--std::unique_lock的使用

目录

1--std::unique_lock的使用

1-1--std::adopt_lock参数

1-2--std::try_to_lock参数

1-3--std::defer_lock参数

1-4--互斥量所有权转移


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));

猜你喜欢

转载自blog.csdn.net/weixin_43863869/article/details/132323167