C++多线程编程第六讲--unique_lock详解

//(1)unique_lock取代lock_guard,unique_lock是一个类模板,比lock_guard更加灵活。
// lock_guard取代了mutex的lock()和unlock()。unique_lock比lock_guard效率低一点,内存占用多一些。

#include<iostream>
#include<thread>
#include<vector>
#include<list>
#include<mutex>

using namespace std;

class A
{
public:
    //把收到的消息,入到一个队列中
    void inMsgRecvQueue()
    {
        int i;
        for (i = 0; i < 100000; ++i)
        {

            cout << "push_back num = " << i << endl;
            //lock之后只能有一个线程可以对msgQueue队列做操作
            //lock_guard<mutex> sbguard(my_mutex);
            unique_lock<mutex> my_unique_lock(my_mutex);
            msgQueue.push_back(i);                   //数字i就是玩家的命令。
        }
    }

    bool outMsgProc(int& command)
    {
        //lock_guard<mutex> sbguard(my_mutex);
        unique_lock<mutex> my_unique_lock(my_mutex);
        if (!msgQueue.empty())
        {
            //消息不为空
            command = msgQueue.front();
            msgQueue.pop_front();          //移除首元素

            return true;
        }
        else
        {
            return false;
        }
    }

    //把数据从消息队列中取出
    void outMsgRecvQueue()
    {
        int i;
        int command = 0;
        for (i = 0; i < 100000; ++i)
        {
            int result = outMsgProc(command);
            if (result == true)
            {
                cout << "command = " << command << endl;
            }
            else
            {
                cout << "msgQueue is empty" << endl;
            }
        }
    }

private:
    list<int> msgQueue;
    mutex my_mutex;       //创建一个互斥量
};

int main()
{
    A myobj;
    thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj));   //保证线程中用的同一个对象
    thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));

    myOutMsg.join();
    myInMsg.join();

    cout << "main thread end..." << endl;
    return 0;
} 

//(2)unique_lock的第二个参数
//(2.1)std::adopt_lock, 表示mutex已经lock。

   #include<iostream>
    #include<thread>
    #include<vector>
    #include<list>
    #include<mutex>
    
    using namespace std;
    
    class A
    {
    public:
        //把收到的消息,入到一个队列中
        void inMsgRecvQueue()
        {
            int i;
            for (i = 0; i < 100000; ++i)
            {
    
                cout << "push_back num = " << i << endl;
                //lock之后只能有一个线程可以对msgQueue队列做操作
                //lock_guard<mutex> sbguard(my_mutex);
                my_mutex.lock();      //要先lock
                unique_lock<mutex> my_unique_lock(my_mutex, std::adopt_lock);
                msgQueue.push_back(i);                   //数字i就是玩家的命令。
            }
        }
    
        bool outMsgProc(int& command)
        {
            //lock_guard<mutex> sbguard(my_mutex);
            my_mutex.lock();    //要先lock
            unique_lock<mutex> my_unique_lock(my_mutex, std::adopt_lock);
    
            if (!msgQueue.empty())
            {
                //消息不为空
                command = msgQueue.front();
                msgQueue.pop_front();          //移除首元素
    
                return true;
            }
            else
            {
                return false;
            }
        }
    
        //把数据从消息队列中取出
        void outMsgRecvQueue()
        {
            int i;
            int command = 0;
            for (i = 0; i < 100000; ++i)
            {
                int result = outMsgProc(command);
                if (result == true)
                {
                    cout << "command = " << command << endl;
                }
                else
                {
                    cout << "msgQueue is empty" << endl;
                }
            }
        }
    
    private:
        list<int> msgQueue;
        mutex my_mutex;       //创建一个互斥量
    };
    
    int main()
    {
        A myobj;
        thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj));   //保证线程中用的同一个对象
        thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));
    
        myOutMsg.join();
        myInMsg.join();
    
        cout << "main thread end..." << endl;
        return 0;
    }

//(2.2)std::try_to_lock, 尝试用mutex的lock去加锁,如果lock不成功,也会立即返回,并不会阻塞在这里。
// 用之前不能在本线程中先lock。

#include<iostream>
    #include<thread>
    #include<vector>
    #include<list>
    #include<mutex>
    
    using namespace std;
    
    class A
    {
    public:
        //把收到的消息,入到一个队列中
        void inMsgRecvQueue()
        {
            int i;
            for (i = 0; i < 100000; ++i)
            {
    
                cout << "push_back num = " << i << endl;
                //lock之后只能有一个线程可以对msgQueue队列做操作
                //lock_guard<mutex> sbguard(my_mutex);
                unique_lock<mutex> my_unique_lock(my_mutex, std::try_to_lock);
                if (my_unique_lock.owns_lock())
                {
                    msgQueue.push_back(i);                   //数字i就是玩家的命令。
                }
                else
                {
                    //没拿到锁做的事情
                    cout << "Do not have lock" << endl;
                }
    
            }
        }
    
        bool outMsgProc(int& command)
        {
            //lock_guard<mutex> sbguard(my_mutex);
            my_mutex.lock();    //要先lock
            unique_lock<mutex> my_unique_lock(my_mutex, std::adopt_lock);
    
            std::chrono::milliseconds dura(2000);          //休息20秒
            std::this_thread::sleep_for(dura);
    
            if (!msgQueue.empty())
            {
                //消息不为空
                command = msgQueue.front();
                msgQueue.pop_front();          //移除首元素
    
                return true;
            }
            else
            {
                return false;
            }
        }
    
        //把数据从消息队列中取出
        void outMsgRecvQueue()
        {
            int i;
            int command = 0;
            for (i = 0; i < 100000; ++i)
            {
                int result = outMsgProc(command);
                if (result == true)
                {
                    cout << "command = " << command << endl;
                }
                else
                {
                    cout << "msgQueue is empty" << endl;
                }
            }
        }
    
    private:
        list<int> msgQueue;
        mutex my_mutex;       //创建一个互斥量
    };
    
    int main()
    {
        A myobj;
        thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj));   //保证线程中用的同一个对象
        thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));
    
        myOutMsg.join();
        myInMsg.join();
    
        cout << "main thread end..." << endl;
        return 0;
    }

//(2.3)std::defer_lock 不能自己先lock,否则会报异常。初始化一个没有加锁的mutex
//(3)unique_lock的成员函数
//(3.1)lock() 手动加锁,配合std::defer_lock使用,但是不必显式的解锁。
//(3.2)unlock() 解锁,可用于处理其他代码时的暂时解锁。

  #include<iostream>
    #include<thread>
    #include<vector>
    #include<list>
    #include<mutex>
    
    using namespace std;
    
    class A
    {
    public:
        //把收到的消息,入到一个队列中
        void inMsgRecvQueue()
        {
            int i;
            for (i = 0; i < 100000; ++i)
            {
                cout << "push_back num = " << i << endl;
                //lock之后只能有一个线程可以对msgQueue队列做操作
                //lock_guard<mutex> sbguard(my_mutex);
                unique_lock<mutex> my_unique_lock(my_mutex, std::defer_lock);  //创建一个没有加锁的unique_lock
                my_unique_lock.lock();
                //处理共享代码...
    
                my_unique_lock.unlock();
                //处理非共享代码...
    
                my_unique_lock.lock();
    
                msgQueue.push_back(i);                   //数字i就是玩家的命令。     
            }
        }
    
        bool outMsgProc(int& command)
        {
            //lock_guard<mutex> sbguard(my_mutex);
            my_mutex.lock();    //要先lock
            unique_lock<mutex> my_unique_lock(my_mutex, std::adopt_lock);
    
            std::chrono::milliseconds dura(2000);          //休息2秒
            std::this_thread::sleep_for(dura);
    
            if (!msgQueue.empty())
            {
                //消息不为空
                command = msgQueue.front();
                msgQueue.pop_front();          //移除首元素
    
                return true;
            }
            else
            {
                return false;
            }
        }
    
        //把数据从消息队列中取出
        void outMsgRecvQueue()
        {
            int i;
            int command = 0;
            for (i = 0; i < 100000; ++i)
            {
                int result = outMsgProc(command);
                if (result == true)
                {
                    cout << "command = " << command << endl;
                }
                else
                {
                    cout << "msgQueue is empty" << endl;
                }
            }
        }
    
    private:
        list<int> msgQueue;
        mutex my_mutex;       //创建一个互斥量
    };
    
    int main()
    {
        A myobj;
        thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj));   //保证线程中用的同一个对象
        thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));

        myOutMsg.join();
        myInMsg.join();

        cout << "main thread end..." << endl;
    }

    //(3.3)try_lock()     尝试给互斥量加锁

    #include<iostream>
    #include<thread>
    #include<vector>
    #include<list>
    #include<mutex>
    
    using namespace std;
    
    class A
    {
    public:
        //把收到的消息,入到一个队列中
        void inMsgRecvQueue()
        {
            int i;
            for (i = 0; i < 100000; ++i)
            {
                cout << "push_back num = " << i << endl;
                //lock之后只能有一个线程可以对msgQueue队列做操作
                //lock_guard<mutex> sbguard(my_mutex);
                unique_lock<mutex> my_unique_lock(my_mutex, std::defer_lock);  //创建一个没有加锁的unique_lock
                if (my_unique_lock.try_lock() == true)
                {
                    msgQueue.push_back(i);                   //数字i就是玩家的命令。
                }
                else
                {
                    cout << "Do not get lock." << endl;
                }
            }
        }
    
        bool outMsgProc(int& command)
        {
            //lock_guard<mutex> sbguard(my_mutex);
            my_mutex.lock();    //要先lock
            unique_lock<mutex> my_unique_lock(my_mutex, std::adopt_lock);
    
            std::chrono::milliseconds dura(2000);          //休息2秒
            std::this_thread::sleep_for(dura);
    
            if (!msgQueue.empty())
            {
                //消息不为空
                command = msgQueue.front();
                msgQueue.pop_front();          //移除首元素
    
                return true;
            }
            else
            {
                return false;
            }
        }
    
        //把数据从消息队列中取出
        void outMsgRecvQueue()
        {
            int i;
            int command = 0;
            for (i = 0; i < 100000; ++i)
            {
                int result = outMsgProc(command);
                if (result == true)
                {
                    cout << "command = " << command << endl;
                }
                else
                {
                    cout << "msgQueue is empty" << endl;
                }
            }
        }
    
    private:
        list<int> msgQueue;
        mutex my_mutex;       //创建一个互斥量
    };
    
    int main()
    {
        A myobj;

        thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj));   //保证线程中用的同一个对象
        thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));
    
        myOutMsg.join();
        myInMsg.join();
    
        cout << "main thread end..." << endl;
        return 0;
    }

//(3.4)release() 返回管理的mutex对象的指针,并释放所有权。unique_lock和mutex不再有关系。
// 如果原来mutex处于加锁状态,那就需要自己去解锁。人们常把锁头锁住代码的多少称为粒度。

 #include<iostream>
    #include<thread>
    #include<vector>
    #include<list>
    #include<mutex>
    
    using namespace std;
    
    class A
    {
    public:
        //把收到的消息,入到一个队列中
        void inMsgRecvQueue()
        {
            int i;
            for (i = 0; i < 100000; ++i)
            {
                cout << "push_back num = " << i << endl;
                //lock之后只能有一个线程可以对msgQueue队列做操作
                //lock_guard<mutex> sbguard(my_mutex);
                unique_lock<mutex> my_unique_lock(my_mutex);
                std::mutex* ptx = my_unique_lock.release();          //互斥量已经加锁,程序员有责任去解锁
    
                msgQueue.push_back(i);                   //数字i就是玩家的命令。
                ptx->unlock();
    
            }
        }
    
        bool outMsgProc(int& command)
        {
            //lock_guard<mutex> sbguard(my_mutex);
            my_mutex.lock();    //要先lock
            unique_lock<mutex> my_unique_lock(my_mutex, std::adopt_lock);
    
            std::chrono::milliseconds dura(2000);          //休息2秒
            std::this_thread::sleep_for(dura);
    
            if (!msgQueue.empty())
            {
                //消息不为空
                command = msgQueue.front();
                msgQueue.pop_front();          //移除首元素
    
                return true;
            }
            else
            {
                return false;
            }
        }
    
        //把数据从消息队列中取出
        void outMsgRecvQueue()
        {
            int i;
            int command = 0;
            for (i = 0; i < 100000; ++i)
            {
                int result = outMsgProc(command);
                if (result == true)
                {
                    cout << "command = " << command << endl;
                }
                else
                {
                    cout << "msgQueue is empty" << endl;
                }
            }
        }
    
    private:
        list<int> msgQueue;
        mutex my_mutex;       //创建一个互斥量
    };
    
    int main()
    {
        A myobj;

        thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj));   //保证线程中用的同一个对象
        thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));
    
        myOutMsg.join();
        myInMsg.join();
    
        cout << "main thread end..." << endl;
        return 0;
    }

//(4)unique_lock所有权的传递
//unique_lock的所有权是可以转移的,但是不能复制。unique也是可以返回的。

#include<iostream>
#include<thread>
#include<vector>
#include<list>
#include<mutex>

using namespace std;

class A
{
public:
    unique_lock<mutex> rtn_unique_lock()            //返回一个unique_lock
    {
        unique_lock<mutex> tmpguard(my_mutex);
        return tmpguard;           //从函数返回一个局部的unique_lock对象是可以的,返回局部对象tmpguard
                                   //会导致系统生成临时的unique_lock对象,并且调用移动构造函数。
    }

public:
    //把收到的消息,入到一个队列中
    void inMsgRecvQueue()
    {
        int i;
        for (i = 0; i < 100000; ++i)
        {
            cout << "push_back num = " << i << endl;
            //lock之后只能有一个线程可以对msgQueue队列做操作
            //lock_guard<mutex> sbguard(my_mutex);
            unique_lock<mutex> my_unique_lock(my_mutex);
            unique_lock<mutex> mu_unique_lock_t(std::move(my_unique_lock));    //移动语意,my_unique_lock就为空了

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

        }
    }

    bool outMsgProc(int& command)
    {
        //lock_guard<mutex> sbguard(my_mutex);
        my_mutex.lock();    //要先lock
        unique_lock<mutex> my_unique_lock(my_mutex, std::adopt_lock);

        std::chrono::milliseconds dura(2000);          //休息2秒
        std::this_thread::sleep_for(dura);

        if (!msgQueue.empty())
        {
            //消息不为空
            command = msgQueue.front();
            msgQueue.pop_front();          //移除首元素

            return true;
        }
        else
        {
            return false;
        }
    }

    //把数据从消息队列中取出
    void outMsgRecvQueue()
    {
        int i;
        int command = 0;
        for (i = 0; i < 100000; ++i)
        {
            int result = outMsgProc(command);
            if (result == true)
            {
                cout << "command = " << command << endl;
            }
            else
            {
                cout << "msgQueue is empty" << endl;
            }
        }
    }

private:
    list<int> msgQueue;
    mutex my_mutex;       //创建一个互斥量
};

int main()
{
    A myobj;

    thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj));   //保证线程中用的同一个对象
    thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));

    myOutMsg.join();
    myInMsg.join();

    cout << "main thread end..." << endl;
    return 0;
}

  

上一篇:bootstrap table 前后端分页(超级简单)


下一篇:算法笔记12:数组去重