ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c++之Mutex 互斥量(互斥锁)

2021-03-07 20:30:26  阅读:354  来源: 互联网

标签:std mutex 递归 lock c++ 互斥 线程 Mutex


文章目录

Mutex 互斥量(互斥锁) 简介

在 C11 标准程序库头文件中定义了一些互斥访问的类与方法等。mutex 又称互斥量。

1.Mutex 系列类(四种)

①std::mutex : 该类表示普通的互斥锁, 不能递归使用。

std::mutex 是 C++11 中最基本的互斥量,用于保护共享数据免受多个线程同时访问的同步原语。,std::mutex对象提供了独占(排他性)所有权的特性,不支持递归地对 std::mutex 对象上锁

std::mutex 的成员函数
(1).构造函数和析构函数:

std::mutex 不允许拷贝构造,也不允许 move 拷贝,最初产生的 mutex 对象是处于 unlocked 状态的。std::~mutex()销毁互斥。若互斥锁被线程占有,或线程在持有互斥锁的所有权时终止,则行为未定义。

(2)加锁函数:lock(),调用线程将锁住该互斥量。线程调用该函数会发生下面 3 种情况:

①. 如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住,直到调用 unlock 之前,该线程一直拥有该锁。
② 如果当前互斥量被其他线程锁住,则当前的调用线程被阻塞住。
③ 如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)。

(3) 尝试加锁 try_lock(),尝试锁住互斥量,如果互斥量被其他线程占有,则当前线程也不会被阻塞。线程调用该函数也会出现下面 3 种情况,
① 如果当前互斥量没有被其他线程占有,则该线程锁住互斥量,直到该线程调用 unlock 释放互斥量。
② 如果当前互斥量被其他线程锁住,则当前调用线程返回 false,而并不会被阻塞掉。
③ 如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)
(4)解锁函数: unlock(), 解锁,释放对互斥量的所有权。

 std::mutex g_mtx; // 程序执行被创建,全局生存期开始。
 void thread_fun()
 {
     g_mtx.lock(); // 拥有所有权
     //
     g_mtx.unlock(); // 释放拥有权
}

②std::recursive_mutex:该类表示递归(再入)互斥锁。递归互斥锁可以被同一个线程多次加锁,以获得对互斥锁对象的多层所有权。

该类表示递归(再入)互斥锁。递归互斥锁可以被同一个线程多次加锁,以获得对互斥锁对象的多层所有权。例如,同一个线程多个函数访问临界区时都可以各自加锁,执行后各自解锁。std::recursive_mutex 释放互斥量时需要调用与该锁层次深度相同次数的 unlock(),即 lock()次数和 unlock()次数相同。可见,线程申请递归互斥锁时,如果该递归互斥锁已经被当前调用线程锁住,则不会产生死锁。此外,std::recursive_mutex 的功能与 std::mutex 大致相同。

③ std::time_mutex: 该类表示定时(有限时间)互斥锁,不能递归使用。

std::timed_mutex 比 std::mutex 多了两个成员函数:
(1)try_lock_for():函数参数表示一个时间范围,在这一段时间范围之内线程如果没有获得锁则保持阻塞;如果在此期间其他线程释放了锁,则该线程可获得该互斥锁;如果超时(指定时间范围内没有获得锁),则函数调用返回 false。

(2)try_lock_until():函数参数表示一个时刻,在这一时刻之前线程如果没有获得锁则保持阻塞;如果在此时刻前其他线程释放了锁,则该线程可获得该互斥锁;如果超过指定时刻没有获得锁,则函数调用返回 false

std::timed_mutex mtx; // (有限时间锁)
 void fireworks(char ch)
 {
      while (!mtx.try_lock_for(std::chrono::milliseconds(200)))//200毫秒内没获得锁则返回false
      {
          std::cout << ch;
      }
      std::this_thread::sleep_for(std::chrono::milliseconds(1000));
      std::cout << "*\n";
      mtx.unlock();
 }

 int main()
 {
     const int n = 3;
     std::thread threads[n];
     char ch = 'A';
     // spawn n threads:
    for (int i = 0; i < n; ++i)
    {
         threads[i] = std::thread(fireworks, ch + i);
    }

    for (auto& th : threads)
    {
        th.join();
    }
     return 0;
}

④ std::recursive_timed_mutex:带定时的递归互斥锁。

2.Lock 类(四种)

一 :lock_guard (锁保护):\

lock_guard 类不可复制(拷贝和赋值)。只有构造和析构函数。
类 lock_guard 是互斥体包装器,为在作用域块期间占有互斥提供便利 RAII 风格机制。创建 lock_guard 对象时,它试图接收给定互斥的所有权。控制离开创建 lock_guard 对象的作用域时,销毁 lock_guard 并释放互斥。

 std::mutex g_mtx;
 void threadfunc(char ch)
 {
     //首先,这在一个局部作用域内, std::lock_guard 在构造时,
     //会调用 g_mutex->lock() 方法;
     std::lock_guard<std::mutex> lock(g_mtx); 
     for (int i = 0; i < 5; ++i)
     {   
         std::lock_guard<std::mutex> lock(g_mtx);     //加锁
         for (int j = 0; j < 5; ++j)
         { // std::lock_guard<std::mutex> lock(g_mtx); 
             printf("%c", ch);
         }
         printf("\n");
     }
     printf("\n");
     //局部作用域代码结束后,
     //std::lock_guard 的析构函数会被调用,
     //函数中会调用 g_mutex->unlock() 方法。
}

 int main()
 {
     char ch = 'a';
     std::thread that[5];
     for (int i = 0; i < 5; ++i)
     {
          that[i] = std::thread(threadfunc, ch + i);
     }
     for (int i = 0; i < 5; ++i)
     {
        that[i].join();
     }
    cout << "Main End" << endl;
    return 0;
 }

二: scoped_lock (范围):

scoped_lock 类不可复制(拷贝和赋值)。只有构造和析构函数。
类 scoped_lock 是提供便利 RAII 风格机制的互斥包装器,它在作用域块的存在期间占有一或多个互斥。创建scoped_lock 对象时,它试图取得给定互斥的所有权。控制离开创建 scoped_lock 对象的作用域时,析构 scoped_lock 并以逆序释放互斥。若给出数个互斥,则使用免死锁算法,如同以 std::lock 。

三:unique_lock (独占,唯一),

有锁定,修改和观察器函数。
类 unique_lock 是通用互斥包装器,允许延迟锁定、锁定的有时限尝试、递归锁定、所有权转移和条件变量一同使用。类 unique_lock 可移动,但不可复制——它满足可移动构造 (MoveConstructible) 和可移动赋值 (MoveAssignable) 但不满足可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 。

std::unique_lock<std::timed_mutex> lock;

四:shared_lock (共享),

有锁定,修改和观察器函数。
类 shared_lock 是通用共享互斥所有权包装器,允许延迟锁定、定时锁定和锁所有权的转移。锁定 shared_lock ,会以共享模式锁定关联的共享互斥( std::unique_lock 可用于以排他性模式锁定)。
shared_lock 类可移动,但不可复制——它满足可移动构造 (MoveConstructible) 与可移动赋值 (MoveAssignable) 的要求,但不满足可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 。共享所有权模式等待于共享互斥,可使用 std::condition_variable_any ( std::condition_variable 要求std::unique_lock 故而只能以唯一所有权模式等待)。

标签:std,mutex,递归,lock,c++,互斥,线程,Mutex
来源: https://blog.csdn.net/qq_46615150/article/details/114494161

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有