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

【多线程】线程互斥 互斥量操作 守卫锁 重入与线程安全

文章目录

  • Ⅰ. 线程互斥概念
  • Ⅱ. 互斥锁的概念
  • Ⅲ. 互斥锁的接口
    • 一、互斥锁的定义
    • 二、初始化互斥锁
    • 三、销毁互斥锁
    • 四、互斥量的加锁和解锁
      • ① 加锁接口
      • ② 解锁接口
    • 五、改进买票系统
    • 💥注意事项
  • Ⅳ. 互斥锁的实现原理
    • 一、问题引入
    • 二、复习知识
    • 三、实现原理
  • Ⅴ. 封装锁对象 && 守卫锁
  • Ⅵ. 重入&&线程安全
    • 一、概念
        • ① 常见的可重入的情况
        • ② 常见的不可重入的情况
        • ③ 常见的线程安全的情况
        • ④ 常见的线程不安全的情况
    • 二、重入与线程安全的联系
    • 三、重入与线程安全的区别

在这里插入图片描述

Ⅰ. 线程互斥概念

线程互斥(Thread Mutex是指在多线程并发执行的程序中,为了避免多个线程同时访问临界区(Critical Section而采用的一种同步机制临界区是指对共享资源进行访问的代码段(也可以参考上面的概念),例如对共享变量的读写操作等。

​ 线程互斥的目的是保证同一时刻只有一个线程能够进入临界区,以防止多个线程同时对共享资源进行修改,导致数据不一致或者结果出错。一般情况下,采用 互斥锁(Mutex,也称为互斥量) 实现线程互斥,也可以使用其他同步机制,如**信号量(Semaphore)、条件变量(Condition Variable)**等。

基本概念总结:

  • 临界资源:多线程执行流共享的资源就叫做临界资源。
  • 临界区:每个线程内部,访问临界资源的代码,就叫做临界区。
  • 互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用。
  • 原子性:不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完成。

​ 下面我们就分别来学习互斥锁(也称为互斥量,为了统一,下面我们都称为互斥锁!)、条件变量、信号量和一些常见的锁情况!

Ⅱ. 互斥锁的概念

互斥锁(mutex是一种基本的线程同步机制,用于解决多个线程访问共享资源时可能发生的竞态条件问题。它可以 保证在同一时刻只有一个线程能够获取锁,并进入临界区。当一个线程获取到互斥锁时,其他线程尝试获取该锁时会被阻塞,直到该线程释放锁。

​ 互斥锁提供了两个基本操作:加锁 && 解锁

  • 加锁操作用于获取锁,防止其他线程进入临界区。
  • 解锁操作用于释放锁,允许其他线程获取锁并进入临界区。

​ 需要注意的是,在使用互斥锁时,应该注意死锁问题。死锁是指两个或多个线程相互等待对方释放锁,导致程序陷入无限等待的状态。 为了避免死锁问题,应该避免在临界区内调用阻塞操作(如等待信号量、等待条件变量等),并且应该尽可能减小临界区的范围,以避免锁竞争问题。

​ 在 C++ 中,互斥量可以使用标准库中的 std::mutex 类来实现。std::mutex 类提供了两个基本操作:lock()unlock(),分别用于获取锁定状态和释放锁定状态。当一个线程获取了锁定状态后,其他线程将不能再获取锁定状态,直到该线程释放锁定状态。

​ 具体的内容请翻阅 C++ 笔记的讲解!

​ 下面我们看一段代码,就能理解为何需要有互斥锁(下面的 thread.hpp 头文件是线程控制笔记中封装的线程库,可以去翻阅,这里直接调用):

#include "thread.hpp"
#include <memory>
#include <unistd.h>int ticket = 10; // 全局变量void* thread_routine(void* args)
{string name = static_cast<const char*>(args);while(true){// 票数大于0则抢票,否则退出if(ticket > 0){usleep(12345); // 1秒=10^3毫秒=10^6微秒cout << "i am new thread, name: " << name << ",the ticket: " << ticket << endl;ticket--;}elsebreak;}
}
int main()
{unique_ptr<Thread> t1(new Thread(thread_routine, (void*)"user1", 1));unique_ptr<Thread> t2(new Thread(thread_routine, (void*)"user2", 2));unique_ptr<Thread> t3(new Thread(thread_routine, (void*)"user3", 3));unique_ptr<Thread> t4(new Thread(thread_routine, (void*)"user4", 4));unique_ptr<Thread> t5(new Thread(thread_routine, (void*)"user5", 5));t1->join();t2->join();t3->join();t4->join();t5->join();return 0;
}

在这里插入图片描述

​ 上述代码是一个模拟抢票的系统,就是多个线程同时对全局变量 ticket 进行减减操作,而 ticket 也就是我们上面所说的临界资源啦,既然多个线程对 ticket 同时进行操作,那么势必会造成一些竞争条件问题,那么到底是怎么发生这个问题的呢❓❓❓

​ 其实就是因为可能会发生这种情况:当多个线程同时来到 if(ticket > 0) 语句进行判断的时候,此时如果 ticket 已经是 1 了,那么此时假设 线程A 进入了这个语句,但是刚进入的时候就发生了一些情况比如说时间片切换CPU突然调度一个优先级更高的线程导致该 线程A 等待的情况,这个时候还没将 ticket</

相关文章:

  • 大模型工业化元年:GPT-5开启通用AI新纪元,中国技术如何破局?
  • 安宝特案例 | 物流仓储头部企业应用AR+作业流,规范日常安全点检,保障消防安全
  • 简单易懂:从零开始训练CLIP模型的实用指南
  • SiamMask原理详解:从SiamFC到SiamRPN++,再到多任务分支设计
  • 数字IC后端项目典型问题之后端实战项目问题记录(2025.04.24)
  • Spark-Streaming核心编程(2)
  • 利用 SSE 实现文字吐字效果:技术与实践
  • 作业。。。。。。
  • Kubernetes 常用运维命令整理
  • 如何用大模型技术重塑物流供应链
  • 智慧景区国标GB28181视频平台EasyGBS视频融合应用全场景解决方案
  • CentOS 7上安装与配置Memcached及PHP客户端使用教程
  • 2025磐石行动第七周WP
  • 5.3.1 MvvmLight以及CommunityToolkit.Mvvm介绍
  • 【win11 安装WSL2 详解一遍过!!】
  • 什么是Wi-SUN?与其他低功耗广域网技术有何区别?
  • 人工智能与机器学习:二元分类决策树构建指南
  • 【Linux】基本指令(下)
  • 第十五届蓝桥杯 2024 C/C++组 拼正方形
  • PowerToys:让你的windows拥有更丝滑的体验
  • 无视规范开“远端”、企业云端被窃密,国安部:莫让运维成运“危”
  • 中国天主教组织发唁电对教皇去世表示哀悼
  • 著名文学评论家、清华大学中文系教授蓝棣之逝世
  • 厚植民营企业家成长土壤是民营经济高质量发展的关键
  • 第四届全民阅读大会·阅读权益保障论坛举办
  • 书信里的宋人|忠奸难辨的夏竦