首页 > 编程语言 >【c++多线程】互斥量概念、用法、死锁演示以及unique_lock

【c++多线程】互斥量概念、用法、死锁演示以及unique_lock

时间:2022-08-27 15:14:14浏览次数:127  
标签:std msgRecvQueue int lock 互斥 死锁 mutex 多线程 my

第5节 互斥量概念、用法、死锁演示及解决详解

  • (1) 互斥量(mutex)的基本概念

  • (2)互斥量的用法

    • (2.1)lock(), unlock()
    • (2.2) std::lock_guard类模板
  • (3) 死锁

    • (3.1) 死锁演示
    • (3.2) 死锁的一般解决方案
    • (3.3) std::lock()函数模板
    • (3.4) std::lock_guard的std::adopt_lock参数

5.0 线程

这样写因为是有问题的,没有保护线程。

#include <iostream>
#include <list>
#include <thread>

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100000; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            this->msgRecvQueue.push_back(i); // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来
        }
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        for (int i = 0; i < 100000; ++i)
        {
            if (!this->msgRecvQueue.empty())
            {
                // 消息不为空
                int command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
                this->msgRecvQueue.pop_front();           // 移除第一个元素,但不返回

                // 这里考虑处理数据
            }
            else
            {
                // 消息队列为空
                cout << "outMsgRuecvQueue()执行,但目前消息队列中为空" << i << endl;
            }
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
};

int main(int argc, char *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

5.1 互斥量(mutex)的基本概念

保护共享数据,操作时,某个用代码把共享数据锁住,其他想操作共享数据的线程必须等待解锁(锁定住,操作,解锁)

5.1.1 互斥量(mutex)的基本概念

互斥量是个类对象,理解成一把锁,多个线程尝试用lock()成员函数来加锁这把锁头,
只有一个线程能锁定成功(成功的标志是lock()函数返回。
如果没锁成功,那么流程卡在lock()这里不断的尝试去锁这把锁。

互斥量使用要小心,保护数据不多不少,少了,没达到保护效果,多了,影响效率。

5.2 互斥量用法

5.2.1 lock(),unlock()

步骤:先lock(),操作共享数据,最后unlock():

lock()unlock()要成对使用,有lock必须要有unlock,每调用一次lock(),必然应该调用一次unlock()

不应该也不允许调用1次lock(),却调用2次unlock(),也不允许调用2次lock()却调用1次unlock(),这些非对称数量的调用都会导致程序不稳定甚至崩溃。

加锁最简单版本:

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            my_mutex.lock();
            this->msgRecvQueue.push_back(i); // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来
            my_mutex.unlock();
        }
    }

    bool outMsgLULProc(int &command)
    {
        my_mutex.lock();
        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回
            my_mutex.unlock();                    // 每个分支都要有unlock
            return true;
        }
        my_mutex.unlock(); // 每个分支都要有unlock
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
};

int main(int argc, char *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

5.2.2 std::lock_guard类模板

为了防止忘记unlock(),引入了一个叫std::lock_guard的类模板。

和智能指针相似(unique_ptr<>),忘记释放内存不要紧,智能指针自己会释放。

std::lock_guard类模板,直接取代lock()unlock(),也就是说,有了lock_guard之后,再不能使用lock()unlock()

这也不用手动unlock

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            std::lock_guard<std::mutex> sbguard(my_mutex);
            this->msgRecvQueue.push_back(i); // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来
        }
    }

    bool outMsgLULProc(int &command)
    {
        std::lock_guard<std::mutex> sbguard(my_mutex);
        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回
            return true;
        }
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

使用大括号{}提前结束锁的周期

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            {
                std::lock_guard<std::mutex> sbguard(my_mutex);
                this->msgRecvQueue.push_back(i); // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来
            }
            // 其他非共享代码
            // .....
        }
    }

    bool outMsgLULProc(int &command)
    {
        std::lock_guard<std::mutex> sbguard(my_mutex);
        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回
            return true;
        }
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

5.3 死锁

死锁问题的产生至少需要两个互斥量才能产生。

比如:

两个互斥量,mutex1和mutex2

两个线程,A和B

  • 线程A执行的时候,这个线程先锁mutex1再锁mutex2
  • 出现上下文切换
  • 线程B执行了,这个线程先锁mutex2,因为mutex2还没有被锁,所以mutex2会锁成功,线程B要去锁mutex1了。。。
  • 这个就出现了死锁
  • 线程A因为拿不到mutex2,流程走不下去
  • 线程B因为拿不到mutex1,流程走不下去

5.3.1 死锁演示

这样写就会出现死锁

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            my_mutex1.lock();   // 实际工程这两个
            my_mutex2.lock();
            this->msgRecvQueue.push_back(i); // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来
            my_mutex2.unlock();
            my_mutex1.unlock();
        }
    }

    bool outMsgLULProc(int &command)
    {
        my_mutex2.lock();
        my_mutex1.lock();
        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回
            my_mutex1.unlock();
            my_mutex2.unlock();
            return true;
        }
        my_mutex1.unlock();
        my_mutex2.unlock();
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
    std::mutex my_mutex1;        // 第一把锁
    std::mutex my_mutex2;        // 第二把锁
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

5.3.2 死锁的一般解决方案

只要线程里面锁的顺序一致就不会出现死锁

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            my_mutex1.lock();   // 实际工程这两个
            my_mutex2.lock();
            this->msgRecvQueue.push_back(i); // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来
            my_mutex2.unlock();
            my_mutex1.unlock();
        }
    }

    bool outMsgLULProc(int &command)
    {
        my_mutex1.lock();
        my_mutex2.lock();
        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回
            my_mutex2.unlock();
            my_mutex1.unlock();
            return true;
        }
        my_mutex1.unlock();
        my_mutex2.unlock();
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
    std::mutex my_mutex1;        // 第一把锁
    std::mutex my_mutex2;        // 第二把锁
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

或者使用std::lock_guard

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            std::lock_guard<std::mutex> sbguard1(my_mutex1);
            std::lock_guard<std::mutex> sbguard2(my_mutex2);
            this->msgRecvQueue.push_back(i); // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来
        }
    }

    bool outMsgLULProc(int &command)
    {
        std::lock_guard<std::mutex> sbguard1(my_mutex1);
        std::lock_guard<std::mutex> sbguard2(my_mutex2);
        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回
            return true;
        }
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
    std::mutex my_mutex1;        // 第一把锁
    std::mutex my_mutex2;        // 第二把锁
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

5.3.3 std::lock() 函数模板

能力:一次锁住两个或者两个以上的互斥量(至少两个,多了不限,一个不行)

它不存在这种因为在两个线程中,因为锁的顺序问题导致死锁的风险问题。

std::lock():如果互斥量中有一个没锁住,它就在那里等着,等所有互斥量都锁住,它才能往下走(返回)。

要么两个互斥量都锁住,要么两个互斥量都没锁住。如果只锁了一个,另一个没锁成功,则它立即把已经锁住的解锁。

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            std::lock(my_mutex1, my_mutex2); //相当于每个互斥量都调用了.lock()
            this->msgRecvQueue.push_back(i); // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来
            my_mutex2.unlock();              // 前面锁住了两个,所以后面都需要解锁
            my_mutex1.unlock();
        }
    }

    bool outMsgLULProc(int &command)
    {
        //相当于每个互斥量都调用了.lock()
        std::lock(my_mutex1, my_mutex2);
        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回
            my_mutex2.unlock();                   // 前面锁住了两个,所以后面都需要解锁
            my_mutex1.unlock();
            return true;
        }
        my_mutex2.unlock(); // 前面锁住了两个,所以后面都需要解锁
        my_mutex1.unlock();
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
    std::mutex my_mutex1;        // 第一把锁
    std::mutex my_mutex2;        // 第二把锁
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

5.3.4 std::lock_guard的std::adopt_lock参数

使用lock_guard主要是为了来解决unlock的问题。

std::adopt_lock是个结构体对象,起一个标记作用,作用就是:表示这个互斥量已经lock(),不需要在std::lock_guard<std::mutex>里面对mutex对象进行再次lock()了。

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            std::lock(my_mutex1, my_mutex2); // 相当于每个互斥量都调用了 .lock()
            std::lock_guard<std::mutex> sbguard1(my_mutex1, std::adopt_lock);
            std::lock_guard<std::mutex> sbguard2(my_mutex2, std::adopt_lock); //这样就不用unlock,因为析构的时候会自动unlock
            this->msgRecvQueue.push_back(i);                                  // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来
        }
    }

    bool outMsgLULProc(int &command)
    {
        std::lock(my_mutex1, my_mutex2); // 相当于每个互斥量都调用了 .lock()
        std::lock_guard<std::mutex> sbguard1(my_mutex1, std::adopt_lock);
        std::lock_guard<std::mutex> sbguard2(my_mutex2, std::adopt_lock); //这样就不用unlock,因为析构的时候会自动unlock
        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回

            return true;
        }
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
    std::mutex my_mutex1;        // 第一把锁
    std::mutex my_mutex2;        // 第二把锁
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

总结,std::lock():一次锁定多个互斥量,谨慎使用(建议一个一个锁)

第六节 unique_lock详解

  • unique_lock 取代lock_quard
  • unique_lock的第二个参数
    • std::adopt_lock
    • std::try_to_lock
    • std::defer_lock
  • unique_lock的成员函数
    • lock()
    • unlock()
    • try_lock()
    • release()
  • unique_lock所有权的传递

6.1 unique_lock 取代lock_quard

unique_lock是个类模板,工作中,一般lock_guard(推荐使用);lock_guard取代了mutexlock()unlock()

unique_locklock_guard灵活很多,效率上差一点,内存占用多一点。

6.2 unique_lock的第二个参数

std::lock_guard<std::mutex> sbguard1(my_mutex1, std::adopt_lock); // adopt_lock标记作用

6.2.1 std::adopt_lock

  • std::adopt_lock:表示这个互斥量已经被lock了(你必须要把互斥量提前lock了,否则会报异常

  • std::adopt_lock标记的效果就是“假设调用方 线程已经拥有了互斥的所有权(已经lock()成功了)”

  • 通知lock_guard不需要在构造函数中lock这个互斥量了;

  • unique_lock也可以带std::adopt_lock标记,含义相同,就是不希望在unique_lock()的构造函数中lock这个mutex

使用adopt_lock需要加锁

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            my_mutex1.lock();
            std::unique_lock<std::mutex> sbguard1(my_mutex1, std::adopt_lock); // 使用adopt_lock之前mutex要加锁
            this->msgRecvQueue.push_back(i);                                   // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来
            // 。。。
            // 其他处理代码
        }
    }

    bool outMsgLULProc(int &command)
    {
        my_mutex1.lock();
        std::unique_lock<std::mutex> sbguard1(my_mutex1, std::adopt_lock);
        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回

            return true;
        }
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
    std::mutex my_mutex1;        // 第一把锁
    std::mutex my_mutex2;        // 第二把锁
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

出现的情况

线程2中加入延迟,如果这样写,一旦进入线程2,连带线程1也会进行等待,也一样卡住了

所以就需要使用到try_to_lock(下一节)

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            my_mutex1.lock();
            std::unique_lock<std::mutex> sbguard1(my_mutex1, std::adopt_lock); // 使用adopt_lock之前mutex要加锁
            this->msgRecvQueue.push_back(i);                                   // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来
            // 。。。
            // 其他处理代码
        }
    }

    bool outMsgLULProc(int &command)
    {
        my_mutex1.lock();
        std::unique_lock<std::mutex> sbguard1(my_mutex1, std::adopt_lock);

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

        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回

            return true;
        }
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
    std::mutex my_mutex1;        // 第一把锁
    std::mutex my_mutex2;        // 第二把锁
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

6.2.2 std::try_to_lock

尝试用mutex的lock()去锁定这个mutex,但如果没有锁定成功,也会立即返回,并不会阻塞在那里,用这个 try_to_lock的前提是自己不能先去lock。

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            // my_mutex1.lock();
            std::unique_lock<std::mutex> sbguard1(my_mutex1, std::try_to_lock); // 使用adopt_lock之前mutex要加锁

            if (sbguard1.owns_lock())
            {
                this->msgRecvQueue.push_back(i); // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来
                // 。。。
                // 其他处理代码
            }
            else
            {
                cout << "inMsgRecvQueue()执行,没有拿到锁,只能干点别的事情" << i << endl;
            }
        }
    }

    bool outMsgLULProc(int &command)
    {
        // my_mutex1.lock();
        std::unique_lock<std::mutex> sbguard1(my_mutex1);

        std::chrono::milliseconds dura(1000);
        std::this_thread::sleep_for(dura); // 休息2s

        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回

            return true;
        }
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
    std::mutex my_mutex1;        // 第一把锁
    std::mutex my_mutex2;        // 第二把锁
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

6.2.3 std::defer_lock

  • 用这个defer_lock的前提是 你不能自己先lock,否则会报异常。(和try_to_lock一样,不能自己lock,用adopt_lock需要自己提前加lock)

  • defer_lock的意思 就是 并没有给mutex加锁:初始化一个没有加锁的mutex,但是后面需要对unique_lock对象进行加锁

  • 我们借着defer_lock的话题,来介绍一些unique_lock的重要成员函数

用刚才有延迟的函数做一下修改,这样改过之后会在线程2那边有等待,也就是线程1会跟着线程2有等待,有阻塞。

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            // my_mutex1.lock();
            std::unique_lock<std::mutex> sbguard1(my_mutex1, std::defer_lock); 
            sbguard1.lock();        // 这边是对sbguard加锁,不用关心解锁,会自己解锁

            // if (sbguard1.owns_lock())
//             {
                this->msgRecvQueue.push_back(i); // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来
                // 。。。
                // 其他处理代码
            // }
            // else
            // {
            //     cout << "inMsgRecvQueue()执行,没有拿到锁,只能干点别的事情" << i << endl;
            // }
        }
    }

    bool outMsgLULProc(int &command)
    {
        // my_mutex1.lock();
        std::unique_lock<std::mutex> sbguard1(my_mutex1);

        std::chrono::milliseconds dura(100);
        std::this_thread::sleep_for(dura); // 休息2s

        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回

            return true;
        }
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
    std::mutex my_mutex1;        // 第一把锁
    std::mutex my_mutex2;        // 第二把锁
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

非阻塞,使用sbguard1.try_lock()

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            // my_mutex1.lock();
            std::unique_lock<std::mutex> sbguard1(my_mutex1, std::defer_lock);
            // sbguard1.lock(); // 这边是对sbguard加锁,不用关心解锁,会自己解锁

            // 因为用了defer_lock,所以这边bguard可以用try_lock 尝试加锁,和try_to_lock相似
            if (sbguard1.try_lock() == true) // 返回true等于拿到锁了
            {
                // 共享代码,需要加锁的地方
                this->msgRecvQueue.push_back(i); // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来

                // 非共享代码,不需要加锁的,可以先解锁,这个就是unique_lock的灵活性
                sbguard1.unlock();
                // 非共享代码
                // 。。。
                // 。。。

                // 下面又开始有共享代码了,需要加锁
                sbguard1.lock();
                // 共享代码
                // 。。。。
                // ......

                // 最后可以解锁,也可以不解锁,因为会自己解锁。
            }
            else
            {
                cout << " 没有拿到锁" << endl;
            }
        }
    }

    bool outMsgLULProc(int &command)
    {
        // my_mutex1.lock();
        std::unique_lock<std::mutex> sbguard1(my_mutex1);

        std::chrono::milliseconds dura(100);
        std::this_thread::sleep_for(dura); // 休息2s

        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回

            return true;
        }
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
    std::mutex my_mutex1;        // 第一把锁
    std::mutex my_mutex2;        // 第二把锁
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

6.3 unique_lock的成员函数

6.3.1 lock()

lock() 加锁

6.3.2 unlock()

unlock 解锁(虽然使用了defer_lock可以不用自己解锁,但是也可以自己去解锁(因为有一些非共享代码要处理,处理完可以在上锁),另外没有上锁的时候不能使用解锁)

比如:

/*
    std::unique_lock<std::mutex> sbguard1(my_mutex1, std::defer_lcok);  // 没有加锁的my_mutex1
    sbguard1.lock();    //咱们不用自己unlock

    。。。。  // 处理共享代码

    sbguard1.unlock();  // 解锁

    。。。。 // 处理非共享代码

    sbguard1.lock();    // 上锁

    。。。。 // 处理共享代码

    // sbguard1.unlock();  // 最后的解锁可有可无
*/

示例代码(会有阻塞):

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            // my_mutex1.lock();
            std::unique_lock<std::mutex> sbguard1(my_mutex1, std::defer_lock);
            sbguard1.lock(); // 这边是对sbguard加锁,不用关心解锁,会自己解锁

            // 共享代码,需要加锁的地方
            this->msgRecvQueue.push_back(i); // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来

            // 非共享代码,不需要加锁的,可以先解锁,这个就是unique_lock的灵活性
            sbguard1.unlock();
            // 非共享代码 
            // 。。。
            // 。。。

            // 下面又开始有共享代码了,需要加锁
            sbguard1.lock();
            // 共享代码
            // 。。。。
            // ......

            // 最后可以解锁,也可以不解锁,因为会自己解锁。

        }
    }

    bool outMsgLULProc(int &command)
    {
        // my_mutex1.lock();
        std::unique_lock<std::mutex> sbguard1(my_mutex1);

        std::chrono::milliseconds dura(100);
        std::this_thread::sleep_for(dura); // 休息2s

        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回

            return true;
        }
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
    std::mutex my_mutex1;        // 第一把锁
    std::mutex my_mutex2;        // 第二把锁
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

6.3.3 try_lock()

尝试给互斥量加锁,如果拿不到锁,则返回false,如果拿到了锁,返回true,这个函数不会阻塞

6.3.4 release()

返回它所管理的mutex对象指针,并释放所有权;也就是说,这个unique_lock和mutex不再有关系。

严格区分unlock()和release()的区别,不要混淆。
如果原来mutex对象处于加锁状态,你有责任接管过来并负责解锁。(release返回的是原始mutex的指针)

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            // my_mutex1.lock();
            std::unique_lock<std::mutex> sbguard1(my_mutex1);
            std::mutex *ptx = sbguard1.release(); //现在需要自己解锁

            this->msgRecvQueue.push_back(i); // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来

            ptx->unlock(); // 需要自己解锁
        }
    }

    bool outMsgLULProc(int &command)
    {
        // my_mutex1.lock();
        std::unique_lock<std::mutex> sbguard1(my_mutex1);

        std::chrono::milliseconds dura(100);
        std::this_thread::sleep_for(dura); // 休息2s

        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回

            return true;
        }
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
    std::mutex my_mutex1;        // 第一把锁
    std::mutex my_mutex2;        // 第二把锁
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

为什么有时候需要unlock(),因为你有lock锁住的代码段越少,执行越快,整个程序运行效率越高
有人也把锁头锁住的代码多少 称为锁的 粒度,粒度一般用粗细来描述;
a)锁住的代码少,这个粒度叫细。执行效率高
b)锁住的代码多,粒度叫粗,那执行效率就低
要学会尽量选择合适粒度的代码来进行保护,粒度太细,可能漏掉共享数据的保护,粒度太粗,影响效率。

选择合适的粒度

6.4 unique_lock所有权的传递

unique_lock 所有权的传递 mutex

std::unique_lock<std::mutex> sbguard1(my_mutex1); // 所有权权概念

sbguard1拥有my_mutex1的所有权

sbguard1可以把自己对mutex(my_mutex1)的所有权转移给其他的unique_lock对象;

所以,unique_lock对象这个mutex的所有权 属于 可以转移,但是不能复制。

方法1:std::move()

方法2:return std::unique_lock<std::mutex>

使用move转移所有权:

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

using namespace std;

class A
{
public:
    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;
            // my_mutex1.lock();
            std::unique_lock<std::mutex> sbguard1(my_mutex1);
            std::unique_lock<std::mutex> sbguard2(std::move(sbguard1)); // 移动语义,现在相当于sbguard2和my_mutex1绑定到一起
                                                                        // 现在sbguard1指向空,sbguard2指向my_mutex1

            this->msgRecvQueue.push_back(i); // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来

        }
    }

    bool outMsgLULProc(int &command)
    {
        // my_mutex1.lock();
        std::unique_lock<std::mutex> sbguard1(my_mutex1);

        std::chrono::milliseconds dura(100);
        std::this_thread::sleep_for(dura); // 休息2s

        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回

            return true;
        }
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
    std::mutex my_mutex1;        // 第一把锁
    std::mutex my_mutex2;        // 第二把锁
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

另一种写法:

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

using namespace std;

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

    // 把收到的消息入到一个队列的线程
    void inMsgRecvQueue()
    {
        for (int i = 0; i < 100; ++i)
        {
            cout << "inMsgRecvQueue()执行,插入一个元素  " << i << endl;

            std::unique_lock<std::mutex> sbguard1 = rtn_unique_lock();

            this->msgRecvQueue.push_back(i); // 假设这个数字i就是我收到的命令,我直接弄到消息队列里边来
        }
    }

    bool outMsgLULProc(int &command)
    {
        // my_mutex1.lock();
        std::unique_lock<std::mutex> sbguard1(my_mutex1);

        std::chrono::milliseconds dura(100);
        std::this_thread::sleep_for(dura); // 休息2s

        if (!this->msgRecvQueue.empty())
        {
            // 消息不为空
            command = this->msgRecvQueue.front(); // 返回第一个元素,但不检查元素是否存在;
            this->msgRecvQueue.pop_front();       // 移除第一个元素,但不返回

            return true;
        }
        return false;
    }

    // 把数据从消息队列中取出的线程
    void outMsgRecvQueue()
    {
        int command = 0;
        // 用while
        while (1)
        {
            bool result = outMsgLULProc(command);
            if (result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素 = " << command << endl;
                // 进行数据处理
                // ....
            }

            //  当全部读取完之后退出
            if (command == 99)
                break;
        }
        cout << "end" << endl;
    }

private:
    std::list<int> msgRecvQueue; // 容器(消息队列),专门用于代表玩家给咱们发送过来的命令
    std::mutex my_mutex;         // 创建一个互斥量
    std::mutex my_mutex1;        // 第一把锁
    std::mutex my_mutex2;        // 第二把锁
};

int main(int argc, char const *argv[])
{

    A myobja;
    std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); // 成员函数作为线程的入口函数
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

    myOutMsgObj.join();
    myInMsgObj.join();

    system("pause");

    return 0;
}

标签:std,msgRecvQueue,int,lock,互斥,死锁,mutex,多线程,my
From: https://www.cnblogs.com/Balcher/p/16630589.html

相关文章

  • UnixBench跑分没有多线程数据的解决办法
    如图,只显示了单核的结果就退出了跑分第一种解决办法是找到UnixBench文件夹下的Run文件,编辑第110行的核数进行修改为自己的服务器核数然后再执行./Run  第二种办法如......
  • 学习:python 了解多线程
    在计算机处理工作时,有时需要多个任务并行处理进程:是对计算机的程序的依稀运行过程的秒数简单的来说编写完毕的代码,在没有运行的时候,称为程序正在运行着的代码,这个运行......
  • 多线程知识
    一、线程概述:线程可以说是一个应用程序或者说是一个软件;线程是一个进程中的场景(进程好比一个公司,线程好比公司里的员工)二、进程与线程的关系一个进程可以创建多......
  • java死锁(Java-level deadlock)
    java-leveldeadlock如下代码可以模拟java死锁。注意:当出现死锁时,应用程序是无响应的。错误信息:FoundoneJava-leveldeadlock:============================="Thread-1......
  • 使用SpringBoot内置多线程
    SpringBoot使用多线程一概述1为什么使用多线程  在我们开发系统过程中,经常会处理一些好费时间的任务(如向数据库中插入上百万数据,将会导致系统阻塞),这个时候就会自然......
  • CountDownLatch demo演示数据分片多线程处理
    #CountDownLatchdemo演示数据分片多线程处理packagecom.example.core.mydemo;importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import......
  • 单例模式+生产者消费者问题+死锁
    真正的多线程开发,降低耦合性多线程就是一个独立的资源类,没有任何附属操作属性和方法     Synchronized和lock区别    线程之间的通信问题:生产者......
  • Java多线程
    1.实现多线程1.1进程和线程【理解】进程:是正在运行的程序​ 是系统进行资源分配和调用的独立单位​ 每一个进程都有它自己的内存空间和系统资源线程:是进程中的单......
  • 浏览器数据库IndexedDB和前端多线程webWorker在3D场景中的实战应用
    背景1.IndexedDB就是浏览器提供的本地数据库,它可以被网页脚本创建和操作。2.在3D场景中模型数据很大,有可能存在数十万级的数据存储,大量数据存储在内存中会很容易导致内......
  • 解决死锁之路 - 常见 SQL 语句的加锁分析
    解决死锁之路-常见SQL语句的加锁分析这篇博客将对一些常见的SQL语句进行加锁分析,看看我们平时执行的那些SQL都会加什么锁。只有对我们所写的SQL语句加锁过程了......