当前位置: 首页 > news >正文

C++多线程学习(三):锁资源管理和条件变量

参考引用

  • C++11 14 17 20 多线程从原理到线程池实战
  • 代码运行环境:Visual Studio 2019

1. 利用栈特性自动释放锁 RAII

1.1 什么是 RAII

  • RAII (Resource Acquisition Is Initialization):使用局部对象来管理资源的技术称为资源获取即初始化
    • 它的生命周期是由操作系统来管理,无需人工介入
    • 资源的销毁容易忘记,造成死锁或内存泄漏

1.2 手动实现 RAII 管理 mutex 资源

  • thread_RAII.cpp

    #include <iostream>
    #include <thread>
    #include <string>
    #include <mutex>
    
    using namespace std;
    
    // RAII
    class XMutex {
    public:
        // 在构造函数中锁住,一生成对象 mux 就拿到锁
        XMutex(mutex &mux) : mux_(mux) {
            cout << "Lock" << endl;
            mux.lock();
        }
        // 析构函数中释放
        ~XMutex() {
            cout << "Unlock" << endl;
            mux_.unlock();
        }
    
    private:
        // 引用方式存储锁,引用必须在初始化时就要赋值
        mutex& mux_;
    };
    
    static mutex mux;
    
    void TextMutex(int status) {
        XMutex lock(mux);  // 不需要关心锁的 unlock() 释放
    
        if (status == 1) {
            cout << " = 1" << endl;
            return;
        } else {
            cout << " != 1" << endl;
            return;
        }
    }  // 超出这个大括号后,会调用析构函数释放栈中资源
    
    int main(int argc, char* argv[]) {
        TextMutex(1);
        TextMutex(2);
    
        getchar();
    
        return 0;
    }
    
  • 控制台输出

    Lock
     = 1
    Unlock
    Lock
     != 1
    Unlock
    

2. lock_guard:C++11 支持的 RAII 管理互斥资源

  • C++11 实现严格基于作用域的互斥体所有权包装器

  • adopt_lock:C++11 类型为 adopt_lock_t,假设调用方已拥有互斥的所有权

  • 通过 {} 控制锁的临界区(栈区间),出了 {} 后自动释放锁资源

  • thread_RAII2.cpp

    #include <thread>
    #include <iostream>
    #include <string>
    #include <mutex>
    
    using namespace std;
    
    static mutex gmutex;
    
    void TestLockGuard(int i) {
        gmutex.lock();
        {
            // 已经拥有锁,不锁定,退出解锁
            lock_guard<mutex> lock(gmutex, adopt_lock);
            // 结束释放锁
        }
        {
            lock_guard<mutex> lock(gmutex);
            cout << "begin thread " << i << endl;
        }
        for (;;) {
            {
                lock_guard<mutex> lock(gmutex);
                cout << "In " << i << endl;
            }
            this_thread::sleep_for(500ms);
        }
    }
    int main(int argc, char* argv[]) {
        for (int i = 0; i < 3; i++) {
            thread th(TestLockGuard, i + 1);
            th.detach();
        }
        getchar();
    
        return 0;
    }
    
  • 控制台输出

    begin thread 1
    In 1
    begin thread 3
    In 3
    begin thread 2
    In 2
    In 1
    In 2
    In 3
    In 1
    ...
    

3. unique_lock:C++11 实现可移动的互斥体所有权包装器

  • 支持临时释放锁 unlock

  • 支持 adopt_lock:(已经拥有锁,不加锁,出栈区会释放)

  • 支持 defer_lock:(延后拥有,不加锁,出栈区不释放)

  • 支持 try_to_lock:尝试获得互斥的所有权而不阻塞,获取失败退出栈区不会释放,通过 owns_lock() 函数判断

  • thread_RAII3.cpp

    #include <thread>
    #include <iostream>
    #include <string>
    #include <mutex>
    
    using namespace std;
    
    int main(int argc, char* argv[]) {
        {
            static mutex mux;
            {
                unique_lock<mutex> lock(mux);
                lock.unlock();  // 临时释放锁
                
                lock.lock();
            }
            {
                // 已经拥有锁 不锁定,退出栈区解锁
                mux.lock();
                unique_lock<mutex> lock(mux, adopt_lock);
            }
            {
                // 延后加锁 不拥有 退出栈区不解锁
                unique_lock<mutex> lock(mux, defer_lock);
                // 加锁 退出栈区解锁
                lock.lock();
            }
            {
                //mux.lock();
                // 尝试加锁 不阻塞 失败不拥有锁
                unique_lock<mutex> lock(mux, try_to_lock);
    
                if (lock.owns_lock()) {
                    cout << "owns_lock" << endl;
                } else {
                    cout << "not owns_lock" << endl;
                }
            }
        }
    
        getchar();
    
        return 0;
    }
    

4. shared_lock C++14 实现可移动的共享互斥体所有权封装器

int main(int argc, char* argv[]) {
    {
        // 共享锁
        static shared_timed_mutex tmux;
    
        // 读取锁--共享锁
        {
            // 调用共享锁 
            shared_lock<shared_timed_mutex> lock(tmux);
            cout << "read data" << endl;
            // 退出栈区 释放共享锁
        }
    
        // 写入锁--互斥锁
        {
            unique_lock<shared_timed_mutex> lock(tmux);
            cout << "write data" << endl;
        }
    }
}

5. 案例:使用互斥锁和 List 实现线程通信

6. condition_variable 读写线程同步

7. 条件变量应用:线程通信解决线程退出时的阻塞问题

相关文章:

  • [Android]使用Git将项目提交到GitHub
  • 使用Java连接Hbase
  • harmonyos应用开发者高级认证考试部分答案
  • 基于Python的新浪微博爬虫程序设计与实现
  • springboot(ssm高校大学生评奖评优系统 奖学金管理系统Java(codeLW)
  • Harmony开发 eTs公共样式抽取
  • C语言——深入理解指针(2)
  • 自定义责任链Filter实现
  • ubuntu22.04 arrch64版操作系统编译zlmediakit
  • 开源博客项目Blog .NET Core源码学习(7:FluentValidation使用浅析)
  • C++类与对象(5)—流运算符重载、const、取地址
  • 番外篇之通讯录
  • Java反射调用kotlin中的类,Object类,Companion对象
  • 专业pdf编辑工具PDF Expert mac中文版特点介绍
  • 【阿里云】图像识别 智能分类识别 项目开发(一)
  • Centos部署GitLab-备份恢复
  • MYSQL加密和压缩函数详解和实战(含示例)
  • hdlbits系列verilog解答(exams/m2014_q4i)-45
  • Deepin使用记录-deepin系统下安装RabbitMq
  • 知行之桥EDI系统HTTP签名验证
  • 深入贯彻中央八项规定精神学习教育中央指导组完成进驻
  • 《瞭望》周刊社原总编辑、党委书记姬斌逝世,享年67岁
  • 人民日报刊文:加快解放和发展新质战斗力
  • 印称一名高级官员在巴基斯坦发动的袭击中死亡
  • 长期对组织隐瞒真实年龄,广元市城发集团原董事韩治成被双开
  • 央行谈MLF:逐步退出政策利率属性回归流动性投放工具