C++11多线程---unique_lock

一、unique_lock取代lock_guard

unique_lock是一个类模板,一般项目之中推荐使用lock_guard。lock_guard取代了lock()与unlock()。unique_lock比lock_guard灵活很多,但是效率上会差一点,内存占用更多。

//
// Created by yangjq on 22-7-7.
//
#include <iostream>
#include <thread>
#include <vector>
#include <list>
#include <mutex>

using namespace std;

class A{
public:
    //把玩家命令收到一个队列的线程
    void inMsgRecvQueue(){
        for(int i = 0; i < 100000; ++i){
            cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
            //std::lock_guard<std::mutex> sbguard(my_mutex1);
            std::unique_lock<std::mutex> sbguard(my_mutex1);

            msgRecvQueue.push_back(i);//数字i就是玩家收到的命令

        }
    }

    bool outMsgLULProc(int &command){
        //std::lock_guard<std::mutex> sbguard(my_mutex1);
        std::unique_lock<std::mutex> sbguard(my_mutex1);
        if(!msgRecvQueue.empty()) {
            //消息不为空
            command = msgRecvQueue.front();//返回前面的元素
            msgRecvQueue.pop_front();

            //处理数据...
            return true;
        }

        return false;

    }


    //数据从消息队列中取出的线程
    void outMsgRecvQueue(){
        int command = 0;
        for(int i = 0; i < 100000; ++i){
            bool result = outMsgLULProc(command);
            if(result){
                cout << "outMsgRecvQueue()执行,删除一个元素!" << endl;
            }
            else{
                cout << "outMsgRecvQueue()执行,消息队列为空" << i << endl;
            }
        }
    }

private:
    //容器,专门用于存储玩家发送过来的命令
    std::list<int> msgRecvQueue;
    std::mutex my_mutex1;
    std::mutex my_mutex2;

};

int main()
{
    //用成员函数作为线程函数的方法来写线程
    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja);
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);
    myInMsgObj.join();
    myOutMsgObj.join();

    cout << "main end !" << endl;
    return 0;
}

二、unique_lock的第二参数

std::adopt_lock  :  表示这个互斥量已经被lock了,因此使用这个参数时,必须把互斥量提前lock,不然程序会出现异常。简单来说就是通知构造类对象时构造函数不需要在lock了,只需要记得析构函数执行时完成unlock即可。这个参数在lock_guard里面也可用。具体使用看下面代码,为什么搞这么复杂呢?因为应用场景复杂,不同的应用场景使用不同的方式会更适合。

std::unique_lock<std::mutex> sbguard(my_mutex1);
等价于
my_mutex1.lock();
std::unique_lock<std::mutex> sbguard(my_mutex1, std::adopt_lock);

std::try_to_lock  :  前提是不能先自己lock()。std::try_to_lock是尝试用mutex的lock()去锁定这个mutex,但如果没有锁定成功,会立即返回,并不会阻塞在那里。在没拿到锁的时间可以执行别的程序,不会卡在那里浪费时间。

std::unique_lock<std::mutex> sbguard(my_mutex1, std::try_to_lock);
if(sbguard.owns_lock()){
    //拿到了锁
    ...执行语句
}
else{
    //没拿到锁
    ...执行语句
}

std::defer_lock  :  前提是不能先自己lock()。defer_lock的意思就是没有给mutex加锁,即初始化了一个没有加锁的mutex。

std::unique_lock<std::mutex> sbguard(my_mutex1);
等价于
std::unique_lock<std::mutex> sbguard(my_mutex1, std::defer_lock);
sbguard.lock();//注意时sbguard加锁,而不是my_mutex1

二、unique_lock的成员函数

上面defer_lock已经提出了unique_lock的一个成员函数lock(),其实unique_lock也有unlock()。应用场景如下:

std::unique_lock<std::mutex> sbguard(my_mutex1, std::defer_lock);
sbguard.lock();//注意时sbguard加锁,而不是my_mutex1
...处理共享数据代码
sbguard.unlock();
...处理其他代码
sbguard.lock();
...处理共享数据代码
//至函数结束,unique_lock会自动再unlock

另外还有成员函数try_lock() : 尝试给互斥量加锁,如果拿不到的话,则返回false,如果拿到了锁,返回true,这个函数不阻塞。和第二参数try_to_lock有点像。

std::unique_lock<std::mutex> sbguard(my_mutex1);
if(sbguard.try_lock()){
    //拿到了锁
    ...执行代码
}
else{
    //没拿到锁
    ...执行代码
}

最后介绍一下release() : 返回它所管理的mutex对象指针,并释放所有权;也就是说,这个unique_lock和mutex不再有关系。

std::unique_lock<std::mutex> sbguard(my_mutex1);
等价于
std::unique_lock<std::mutex> sbguard(my_mutex1);
std::mutex *ptx = sbguard.release();//解除关系,返回的是my_mutex1的指针。
...执行语句
ptx->unlock();//解除了unique_lock与my_mutex1的关系,那么就要自己unlock()。

总的来说,unique_lock进行lock和unlock更加的灵活,因此可以尽可能的控制需要锁住多少代码,更加灵活。

四、unique_lock所有权的传递

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

所有权概念:对于上面的一行代码,sbguard拥有my_mutex1的所有权。

因此unique_lock所有权的传递就是sbguard对于my_mutex1的所有权是可以传递的,但是不能复制。传递方式如下

std::unique_lock<std::mutex> sbguard(my_mutex1);
//sbguard2接管了sbguard对my_mutex1的所有权
std::unique_lock<std::mutex> sbguard2(std::move(sbguard));//进行转移

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C++中,`std::unique_lock`是一个灵活的互斥量封装类,用于处理多线程同步问题。它提供了更多的灵活性和功能,比起`std::lock_guard`更常用。 以下是一个使用`std::unique_lock`解决多线程问题的示例: ```cpp #include <iostream> #include <thread> #include <mutex> std::mutex mtx; // 定义一个互斥量 void printMessage(const std::string& message) { std::unique_lock<std::mutex> lock(mtx); // 创建一个unique_lock并锁住互斥量 for (int i = 0; i < 5; ++i) { std::cout << message << std::endl; } lock.unlock(); // 解锁互斥量 } int main() { std::thread t1(printMessage, "Thread 1"); std::thread t2(printMessage, "Thread 2"); t1.join(); t2.join(); return 0; } ``` 在上述示例中,我们定义了一个全局的`std::mutex`对象`mtx`作为互斥量。然后,我们创建了两个线程`t1`和`t2`,并且每个线程调用`printMessage`函数来输出一定次数的消息。 在`printMessage`函数中,我们首先创建了一个`std::unique_lock<std::mutex>`对象`lock`,并且通过构造函数将互斥量`mtx`作为参数传递进去。这样,`lock`对象会自动锁住互斥量,确保只有一个线程能够进入临界区。 在临界区内,我们输出了一定次数的消息。由于互斥量的保护,每个线程会按照顺序输出自己的消息,避免了竞争条件。最后,我们调用`lock.unlock()`手动解锁互斥量。 在`main`函数中,我们创建了两个线程并启动它们,然后通过`join()`函数等待线程结束。 通过使用`std::unique_lock`,我们可以更灵活地控制互斥量的锁定和解锁时机,并且提供了更多的同步操作,比如条件变量等。这样可以有效地处理多线程之间的同步和竞争条件问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿巴乾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值