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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#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。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#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。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#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() 解锁,可用于处理其他代码时的暂时解锁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#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()     尝试给互斥量加锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#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处于加锁状态,那就需要自己去解锁。人们常把锁头锁住代码的多少称为粒度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#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也是可以返回的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#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;
}

  

posted on   xcxfury001  阅读(391)  评论(0编辑  收藏  举报

编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示