C++ concurrent multithreading -- use of std::unique_lock

Table of contents

1--Use of std::unique_lock

1-1--std::adopt_lock parameter

1-2--std::try_to_lock parameter

1-3--std::defer_lock parameter

1-4--mutex ownership transfer


1--Use of std::unique_lock

Commonly used member functions:

        ① lock(): lock;

        ② unlock(): unlock;

        ③ try_lock(): Try to lock the mutex without blocking, return true when acquiring the lock, otherwise return false;

        ④ release(): Return the object pointer of the managed mutex, and release the ownership, that is, when the std::unique_lock object uses release, the object will no longer have any relationship with the mutex; if the original mutex is in lock() before releasing the relationship state, the std::unique_lock object is no longer responsible for automatically unlocking the mutex (), and the programmer is responsible for manually unlocking the mutex; 

std::unique_lock<std::mutex> guard1(my_mutex1)
std::mutex *ptr = guard1.release();
...
// 需手动解锁
ptr->unlock();

1-1--std::adopt_lock parameter

        Similar to std::adopt_lock in std::lock_guard, when mutex is manually locked (), std::unique_lock can use std::adopt_lock to tell not to use the constructor to automatically lock (), but only to unlock () operate;

        When a thread uses std::adopt_lock, the thread itself must first perform the lock() operation;

// 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 parameter

        When a thread cannot acquire the lock at any time using std::unique_lock, it can use std::try_to_lock to try to acquire the lock . If the acquisition is successful, the contents of the critical section will be executed. If the lock cannot be acquired, the thread can be allowed to do other work, not for now. Critical section work;

        When a thread uses std::try_to_lock, the thread itself cannot perform the lock() operation first;

        In the following code example, the thread fetching data will rest for a period of time after acquiring the lock. At this time, the thread sending data cannot acquire the lock and can only wait;

        When using the std::try_to_lock parameter, the thread sending the data will try to acquire the lock . If the acquisition is successful, the content of the critical section will be executed and the data will be sent to the message queue; if the acquisition fails , the content of the else statement will be executed until the lock is acquired. ;

#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 parameter

       std::unique_lock When using std::defer_lock, it will not lock() the bound mutex. The function is to bind the mutex to the thread , and then consider whether to manually perform the lock() operation according to the situation;          

        When a thread uses std::defer_lock, the thread itself cannot perform the lock() operation first;

1-4--mutex ownership transfer

        The ownership of the std::unique_lock object on the mutex can be transferred through std::move; in the following code, guard2 will own the ownership of my_mutex1, and guard1 will point to null;

std::unique_lock<std::mutex> guard1(my_mutex1);

std::std::unique_lock<std::mutex> guard2(std::move(guard1));

Guess you like

Origin blog.csdn.net/weixin_43863869/article/details/132323167