博客
关于我
C++并发与多线程学习笔记--互斥量、用法、死锁概念
阅读量:459 次
发布时间:2019-03-06

本文共 2398 字,大约阅读时间需要 7 分钟。

互斥量与死锁的技术解析

互斥量的基本概念

互斥量(Mutex)是一种用于线程保护共享资源的机制。其核心思想是:当一个线程使用代码对共享数据加锁时,其他线程必须等待,直到当前线程释放锁才能继续操作。这是一种互斥访问的机制,防止数据竞态和并发错误。

互斥量的本质是一个类对象,代表一把锁。多线程之间通过调用lock()成员函数来竞争这把锁,只有一个线程能够成功加锁。如果某个线程在加锁过程中遇到阻力(例如已被占用的锁),它将卡在lock()函数那里,无法继续执行。这就是所谓的死锁现象。

互斥量的用法

在使用互斥量之前,需要包含相应的头文件:

#include 

lock()和unlock()

互斥量的基础操作是lock()和unlock()。线程在对共享数据进行操作之前,应该调用lock()加锁;操作完成后,必须调用unlock()释放锁。lock()和unlock()必须成对使用,不能出现不成对的情况。例如:

class ProcessRequest {private:    std::list
m_msgRecvQueue; std::mutex my_mutex; public: void inMsgRecvQueue() { for (int i = 0; i < 100000; ++i) { my_mutex.lock(); std::cout << "插入一个元素" << std::endl; m_msgRecvQueue.push_back(i); my_mutex.unlock(); } } bool outMsgLULProc(int &command) { if (!m_msgRecvQueue.empty()) { int command = m_msgRecvQueue.front(); m_msgRecvQueue.pop_front(); return true; } return false; } void outMsgRecvQueue() { int command = 0; for (int i = 0; i < 100000; ++i) { my_mutex.lock(); bool result = outMsgLULProc(command); if (result == true) { std::cout << "outMsgRecvQueue() 执行,取出一个元素" << std::endl; } else { std::cout << "outMsgRecvQueue() 还执行,但是消息队列为空" << std::endl; } my_mutex.unlock(); } }};

std::lock_guard的优势

为了避免开发者忘记释放锁,C++提供了std::lock_guard类模板。它在构造时自动调用Mutex::lock(),而在析构时自动调用Mutex::unlock()。因此,lock_guard可以直接替代传统的lock()和unlock(),使用更为方便和安全。

std::lock_guard的使用方式如下:

std::lock_guard
my_lock(my_mutex);// 加锁自动执行// ...// 解锁自动执行

注意:使用std::lock_guard后,不能再手动调用lock()或unlock(),这将导致错误。

死锁的概念

死锁是指两个或多个线程因占有互斥资源而阻塞,彼此无法继续执行的状态。死锁通常发生在多个线程竞争有限资源(如打印机和输入设备)时。例如:

  • 线程A占有金锁,试图锁定银锁。
  • 线程B占有银锁,试图锁定金锁。
  • 两个线程都无法继续执行,导致系统陷入僵局。

死锁的特征

  • 至少两个进程(线程)参与
  • 所有进程都在等待资源
  • 至少有两个进程占有资源
  • 死锁进程是系统当前进程的子集
  • 死锁会浪费系统资源,可能导致系统崩溃
  • 死锁的解决方案

    为了避免死锁,必须确保互斥锁的使用顺序一致。例如:

    Processor1:{    mutex1.lock();    mutex2.lock();    // ... 其他操作 ...    mutex1.unlock();    mutex2.unlock();}Processor2:{    mutex1.lock();    mutex2.lock();    // ... 其他操作 ...    mutex1.unlock();    mutex2.unlock();}

    std::lock函数模板

    在某些情况下,可能需要直接调用std::lock()函数模板来加锁:

    std::lock(&my_mutex);// 操作共享数据std::unlock(&my_mutex);

    std::lock_guard的std::adopt_lock参数

    std::lock_guard支持一个叫做std::adopt_lock的参数。它允许在构造函数外传入已经加锁的Mutex对象,这样不会重复加锁。这种方式可以提高性能,特别是在多级锁的情况下。

    参考文献

    你可能感兴趣的文章
    PostgreSQL 10.0 preview 变化 - pg_xlog,pg_clog,pg_log目录更名为pg_wal,pg_xact,log
    查看>>
    PostgreSQL 10.1 手册_部分 II. SQL 语言_第 15章 并行查询_15.2. 何时会用到并行查询?...
    查看>>
    PostgreSQL 10.1 手册_部分 II. SQL 语言_第 9 章 函数和操作符_9.23. 行和数组比较
    查看>>
    PostgreSQL 10.1 手册_部分 III. 服务器管理_第 21 章 数据库角色
    查看>>
    Qt开发——网络编程UDP网络广播软件之服务器端
    查看>>
    Postgresql 12.9如何配置允许远程连接
    查看>>
    PostgreSQL 9.6 同步多副本 与 remote_apply事务同步级别 应用场景分析
    查看>>
    Postgresql CopyManager 流式批量数据入库
    查看>>
    PostgreSQL cube 插件 - 多维空间对象
    查看>>
    PostgreSQL Daily Maintenance - cluster table
    查看>>
    PostgreSQL on Linux 最佳部署手册
    查看>>
    PostgreSQL Oracle 兼容性之 - pipelined
    查看>>
    PostgreSQL Point-In-Time Recovery (Incremental Backup)
    查看>>
    postgresql Streaming Replication监控与注意事项
    查看>>
    postgresql 不需要付费_使用数据传输在PostgreSQL执行 外部连接运算符
    查看>>
    postgresql 主从配置_生产环境postgresql主从环境配置
    查看>>
    postgresql 函数&存储过程 ; 递归查询
    查看>>
    PostgreSQL 分组聚合查询中 filter 子句替换 case when
    查看>>
    PostgreSQL 同步流复制锁瓶颈分析
    查看>>
    PostgreSQL 备份与还原命令 pg_dump
    查看>>