栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++11多线程---unique

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++11多线程---unique

一、unique_lock取代lock_guard

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

//
// Created by yangjq on 22-7-7.
//
#include 
#include 
#include 
#include 
#include 

using namespace std;

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

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

        }
    }

    bool outMsgLULProc(int &command){
        //std::lock_guard sbguard(my_mutex1);
        std::unique_lock 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 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 sbguard(my_mutex1);
等价于
my_mutex1.lock();
std::unique_lock sbguard(my_mutex1, std::adopt_lock);

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

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

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

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

二、unique_lock的成员函数

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

std::unique_lock 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 sbguard(my_mutex1);
if(sbguard.try_lock()){
    //拿到了锁
    ...执行代码
}
else{
    //没拿到锁
    ...执行代码
}

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

std::unique_lock sbguard(my_mutex1);
等价于
std::unique_lock 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 sbguard(my_mutex1);

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

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

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1009737.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号