zoukankan      html  css  js  c++  java
  • C++11------unique_lock

    unique_lock

    unique_lock独占的是mutex对象,就是对mutex锁的独占。
    用法:
    (1)新建一个unique_lock 对象
    (2)给对象传入一个std::mutex 对象作为参数;

    std::mutex mymutex;
    unique_lock lock(mymutex);

    因此加锁时新建一个对象lock,而这个对象生命周期结束后自动解锁。

    #include <iostream>
    #include<thread>
    #include<unistd.h>
    #include<mutex>
    using namespace std;
    std::mutex mymutex;
    void sayHello()
    {
        int k=0;
        unique_lock<mutex> lock(mymutex);
        while(k<2)
        {
            k++;
            cout<<endl<<"hello"<<endl;
            sleep(2);
        }
    }
    void sayWorld()
    {
        unique_lock<mutex> lock(mymutex);
        while(1)
        {
             cout<<endl<<"world"<<endl;
             sleep(1);
        }
    }
    int main()
    {
       thread threadHello(&sayHello);
       thread threadWorld(&sayWorld);
       threadHello.join();
       threadWorld.join();
       return 0;
    }

    std::unique_lock

           unique_lock也可以加std::adopt_lock参数,表示互斥量已经被lock,不需要再重复lock。该互斥量之前必须已经lock,才可以使用该参数。

    std::try_to_lock

           可以避免一些不必要的等待,会判断当前mutex能否被lock,如果不能被lock,可以先去执行其他代码。这个和adopt不同,不需要自己提前加锁。举个例子来说就是如果有一个线程被lock,而且执行时间很长,那么另一个线程一般会被阻塞在那里,反而会造成时间的浪费。那么使用了try_to_lock后,如果被锁住了,它不会在那里阻塞等待,它可以先去执行其他没有被锁的代码。

    #include "pch.h"
    #include <iostream>
    #include <thread>
    #include <vector>
    #include <list>
    #include <mutex>
    using namespace std;
    class A_Mutex {
    public:
     
        void inMsgRecvQueue()  //把收到的消息(玩家命令)到一个队列的线程。100000次便于观察
        {
            for (int i = 0; i < 100000; i++)
            {
                cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
     
                {   //加上大括号可以让lock_guard提前(在处理其他代码前)解锁(超出作用域时(大括号)析构)
                    //lock_guard <mutex> guard(my_mutex);
                    //unique_lock <mutex> u_lock(my_mutex);  //unique_lock
     
                    /*
                    //try_to_lock
                    unique_lock <mutex> u_lock_try(my_mutex,try_to_lock);
                    if (u_lock_try.owns_lock())
                    {
                        //拿到了锁
                        msgRecvQueue.push_back(i);
                        //....处理其他代码
                    }
                    else
                    {
                        //没拿到锁
                        cout << "inMsgRecvQueue()执行,但没拿到锁,只能干别的事" << i << endl;
                    }
                    */
     
                    unique_lock <mutex> u_lock_defer(my_mutex, defer_lock);   //没有加锁的my_mutex
     
     
                    /* 
                    //lock与unlock的使用
                    u_lock_defer.lock();    //调用u_lock_defer的成员函数lock(),自带解锁,自己手工解锁也不会有问题(但画蛇添足)
                    
                    
                    u_lock_defer.unlock(); //因为有一些非共享代码要处理,手工暂时解锁,体现灵活性
                    //处理一些非共享代码
                    u_lock_defer.lock(); //处理完后,再重新加锁
                    //再次加锁后,再处理共享代码
                    */
     
                    //成员函数try_lock
                    if (u_lock_defer.try_lock() == true)
                    {
     
                        //拿到了锁
                        msgRecvQueue.push_back(i);
                        //....处理其他代码
                    }
                    else
                    {
                        //没拿到锁
                        cout << "inMsgRecvQueue()执行,但没拿到锁,只能干别的事" << i << endl;
                    }
     
                    msgRecvQueue.push_back(i);
     
                    //...处理代码
                    //msgRecvQueue.push_back(i); //假设这个数字i就是我收到的命令,直接送到消息队列里去
                    
                }
                //....处理其他代码
            }
            return;
        }
     
        bool outMsgLULProc(int &command)
        {
            //lock_guard <mutex> guard(my_mutex);   //guard为对象名,使用lock_guard时,lock与unlock不能再使用
            unique_lock <mutex> u_lock(my_mutex);  
            //std::chrono::milliseconds dura(20000); //20000毫秒==20秒
            //std::this_thread::sleep_for(dura);  //sleep 20s
            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++)
            {
                if (outMsgLULProc(command) == true)
                {
                    cout << "outMsgRecvQueue()执行" << i << endl;
                    //可以对command进行数据处理
                }
                else
                {
                    //消息队列为空
                    cout << "outMsgRecvQueue()执行,但目前消息队列为空" << i << endl;
                }
            }
            cout << "end" << endl;
            return;
        }
    private:
        list <int> msgRecvQueue; //容器(消息队列),专门用于代表玩家发送过来的命令
        mutex my_mutex; //创建了一个互斥量(一个锁)
     
    };
     
    int main()
    {
        A_Mutex myobj_mutex;
        thread myOutnMsgObj(&A_Mutex::outMsgRecvQueue, &myobj_mutex);  //第二参数是引用(就无需拷贝),才能保证线程里用的是同一对象
        thread myInMsgobj(&A_Mutex::inMsgRecvQueue, &myobj_mutex);
        myOutnMsgObj.join();
        myInMsgobj.join();
     
        //一:unique_lock取代lock_guard :  unique_lock <mutex> u_lock(my_mutex); 取代  lock_guard <mutex> guard(my_mutex);
        //unique_lock是个类模板。工作中,一般lock_guard()足够了,推荐使用。
        //unique_lock比lock_guard灵活很多;效率上差一点,内存占用多一点
     
        //二:unique_lock的第二个参数
        
        //(2.1)std::adopt_lock
        //用adopt_lock的前提是互斥量已被lock,通知lock_guard的构造函数无需再lock
        //lock_guard的第二个参数:lock_guard <mutex> guard(my_mutex,std::adopt_lock);   //adopt_lock 起标记作用
        //unique_lock也可以带std::adopt_lock参数,含义相同
        
        //(2.2)std::try_to_lock
        //会尝试用mutex的lock去锁定这个mutex,但如果没有锁定成功,也会立即返回,并不会一直阻塞
        //用try_to_lock的前提是不能自己手动去lock
     
        //(2.3)std::defer_lock
        //用defer_lock的前提是不能自己手动去lock(同try_to_lock)
        //使用它并不会给mutex加锁,作用是初始化了一个没有加锁的mutex
     
        //三:unique_lock的成员函数
        //(3.1)lock(),加锁
        //(3.2)unlock(),解锁,虽然成员函数lock()自带解锁,但unlock可以更加灵活(比如有一些非共享代码要处理:可以暂时解锁再加锁)
        //(3.3)try_lock(),尝试给互斥量加锁,如果拿不到锁,则返回false(不阻塞),如果拿到了锁,返回true。
        //(3.4)release(),返回它所管理的mutex对象指针,并释放所有权;也就是说,这个unique_lock和mutex不再有关系
        //如果原来mutex对象处于加锁状态,需接管过来并负责解锁
     
        //lock锁住的代码段越少,执行越快,整个程序运行效率越高
        //锁住的代码的多少称为锁的 粒度。粒度一般用粗细来描述
        //选择合适的粒度,是高级程序员的能力和实力的体现
     
        //四:unique_lock所有权的传递 
        //unique_lock <mutex> u_lock_defer(my_mutex);    所有权概念: u_lock_defer拥有my_mutex的所有权
        //u_lock_defer可以把自己对my_mutex的所有权 转移 给其他的unique_lock对象,但是不能 复制
        //转移:unique_lock <mutex> u_lock_defer2(std::move(u_lock_defer));    //移动语义,相当于u_lock_defer2与my_mutex绑定在一起了。u_lock_defer则指向空,u_lock_defer2指向空 
     
     
        cout << "主线程执行完毕" << endl; //执行完这句,主线程退出
        return 0; 
    }
  • 相关阅读:
    如何使用Flannel搭建跨主机互联的容器网络
    移动端——touch事件
    Javascript 模块化指北
    vue重构--H5--canvas实现粒子时钟
    redux-saga框架使用详解及Demo教程
    前端代码编写规范
    探秘JS的异步单线程
    POJ 3714 Raid 近期对点题解
    EditText把回车键变成搜索
    Swift语言概览
  • 原文地址:https://www.cnblogs.com/lovebay/p/14430687.html
Copyright © 2011-2022 走看看