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

原文链接: https://www.cnblogs.com/lovebay/p/14430687.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/208344

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 下午11:21
下一篇 2023年2月12日 下午11:21

相关推荐