Linux复习 / 线程相关----线程互斥 QA梳理

news2024/11/24 16:05:08

文章目录

    • 前言
      • 线程互斥
        • Q:什么是临界资源?临界区呢?
        • Q:什么是互斥?
        • Q:数据不一致的本质是什么?
        • Q:用锁对共享资源进行保护的前提是:锁也要作为共享资源被其他线程使用。那么用锁保护共享资源的本质是:用共享资源保护共享资源,这合理吗?
        • Q:lock的原子操作是怎样实现的?
        • Q:死锁的四个必要条件是什么?如何避免死锁?
      • 可重入与线程安全
        • Q:什么是可重入?它与线程安全的关系是什么?

前言

本篇博客梳理关于线程相关的Q&A,主要关注访问共享资源时,涉及到的线程互斥性。若读者也在复习这块知识,或者正在学习这块知识,可以通过这些Q&A检测自己的知识掌握情况。此外,思维导图已经更新至我的gitee,Q&A之外的体系梳理还请移步思维导图。

线程互斥

Q:什么是临界资源?临界区呢?

A:由于进程下的线程共享同一进程地址空间,对于进程下的共享资源,每个线程都可以低成本的访问。但由于线程并发的存在,多线程同时访问共享资源可能造成数据不一致的问题,进而导致严重的bug。而解决这一问题的方法是:将共享资源转换成临界资源,当一个线程访问临界资源时,其他线程无法访问。也就是说,临界资源是同一时刻只允许一个线程访问的资源。而访问临界资源的代码块就被成为临界区。

Q:什么是互斥?

A:同一时刻只允许一个线程访问的资源,我们称该资源具有互斥性。临界资源具有互斥性。

Q:数据不一致的本质是什么?

A:线程访问共享资源时,相关操作不是原子操作!也就是不具有原子性。线程对共享资源的操作执行一半时,就被操作系统切走,在该线程重新被调度之前,其他线程对该共享资源的操作无效。

Q:用锁对共享资源进行保护的前提是:锁也要作为共享资源被其他线程使用。那么用锁保护共享资源的本质是:用共享资源保护共享资源,这合理吗?

A:首先,锁确实是一个共享资源。但是多线程并发访问共享资源带来的数据不一致问题的本质原因不是:该资源是否是共享资源,而是:访问共享资源的操作是否具有原子性!我们对mutex的所有操作都是原子的,即使mutex是一个共享资源,但原子操作可以保证其数据一致,不会出现错误。也就是说,pthread线程库将所有mutex的操作设计成原子操作,以保证mutex的绝对安全。

Q:lock的原子操作是怎样实现的?

A:
image.png
这是上锁过程的伪代码。简单理解一下代码

  • movb $0, %al:将0加载到al寄存器中
  • xchgb %al, mutex:将al寄存器的内容与mutex交换。mutex是锁的一个变量,其值为1
  • 判断al寄存器的值是否为0。
    • 若不为0,则lock成功
    • 若为0,则lock失败,线程被挂起
  • 当线程被唤醒后,会重新执行一次lock

其中的关键是xchgb这条指令,这是一个由内核实现的原子操作,也就是说交换过程要么已经完成,要么没有发生。正是xchgb的原子性,整个lock接口也具有了原子性。

一把互斥锁只有一个值为1的mutex变量,线程想要上锁就要加载0到寄存器,将0和mutex进行交换。而0很廉价,每个线程都能有0,都拿着0与互斥锁的1进行交换,但是一旦1被某个线程交换走,其他线程交换得到的就是被用来交换的0了。而只有交换得到1的线程才能lock成功,其他线程会陷入阻塞,并且被唤醒后会重复这一过程(直到al寄存器交换到1为止)。

这就是lock上锁的过程,其中有一个问题,如果al寄存器一直交换到0,那么调用lock的线程就会不停的重复这个过程。这样的现象叫做死锁。

Q:死锁的四个必要条件是什么?如何避免死锁?

A:

  1. 互斥条件:多线程并发访问共享资源,但同一时刻只允许一个线程访问临界资源
  2. 不剥夺条件:除非持有锁的线程自己释放锁,否则其他线程无法剥夺该线程持有的锁
  3. 请求与保持条件:持有锁的线程继续请求其他锁资源,若因此陷入阻塞,其他线程一定无法获取其持有的锁资源
  4. 循环等待条件:线程之间请求锁的请求关心构成循环。最简单的循环就是A和B两个线程同时请求对方持有的锁资源,此时双方都陷入阻塞,构成了死锁
  • 破坏以上四种关系中的任意一种即可避免死锁,一般情况下,我们只能破坏条件三和条件四
  • 加锁顺序一致与资源一次性分配:破坏循环等待条件,减小线程占用彼此锁资源的概率
  • 及时释放锁资源:破坏请求与保持条件。加锁的粒度越细越好,这不仅是为了提高程序的运行效率,也是为了避免死锁

可重入与线程安全

Q:什么是可重入?它与线程安全的关系是什么?

A:可重入是指:可以在被中断后继续执行(重复进入),并且不会发生错误的函数或者代码段。比如线程A正在调用某一函数或者代码段,调用到一半被cpu切走,此时线程B也调用了该函数(也可以不调用该函数,只是正常的运行)。当cpu恢复线程A时,线程A继续执行代码且执行完成后,程序不会发生错误(数据不一致,内存泄漏),此时我们称该函数或者代码段具有可重入性。

线程安全是指:在多线程并发的场景下,程序不会出现数据/结果不一致的情况。这些情况多发生在线程访问静态变量与全局变量(共享资源)时。

可重入的函数/代码段一定是线程安全的,但线程安全的程序中,函数/代码段不一定是可重入的,因为它可能添加了访问控制。

需要注意的是:可重入与不可重入没有优劣之分,它们只是区分代码的两个性质。若要实现线程安全,可以对不可重入的代码添加访问控制。本质就是建立临界区,保护共享资源。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/425295.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

独家 | 招商银行:玩转校园招聘新方式 挖掘金融科技新人才

数字经济时代,金融科技人才队伍的引进与培养是招商银行人才体系建设的关键任务。 01.金融科技校招2大核心课题 招商银行数字化转型过程中,线上化、生态化、平台化、智能化、数据化全面加速发展,对人才队伍能力提出新要求。 2大核心课题&am…

Git的一些使用

虽然说这也不是啥重要的内容,但是作为计算机人也得学学,了解了解。 一些预备内容 首先得下载git,这个就不多说了。 安装完了之后,首先要做的就是设置用户名称和邮箱地址,因为每次Git提交都会使用该信息,…

I.MX6ULL_Linux_驱动篇(33) pinctrl与gpio子系统

上一章我们编写了基于设备树的 LED 驱动,但是驱动的本质还是没变,都是配置 LED 灯所使用的 GPIO 寄存器,驱动开发方式和裸机基本没啥区别。 Linux 是一个庞大而完善的系统,尤其是驱动框架,像 GPIO 这种最基本的驱动不可…

Linux实战学习

文章目录一、Linux权限信息权限控制信息chmodifconfigpingnmap netstatps killzip unzip常用快捷键二、搭建Java环境yumJDKTomcatMysql三、部署Web项目到服务器一、Linux权限信息 Linux中,拥有最大权限的账户为: root(超级管理员),而普通用户在很多地方…

UWB成为智慧工厂时代的代表技术

UWB成为智慧工厂时代的代表技术 随着智慧工厂的到来,在人员安全问题较为重要的行业中,为了避免人员安全事故的出现,各家企业都逐步装备了UWB定位系统。UWB信号的辐射非常低,通常只有手机辐射的千分之一,因此在工业上应…

【 Spring MVC 核心功能(二) - 获取参数(上)】

文章目录一、获取单个参数二、获取多个参数三、获取对象四、后端参数重命名4.1 使用 RequestParam 重命名参数4.2 RequestParam 中参数必传4.3 设置非必传参数五、使用 PathVariable 获取URL中参数一、获取单个参数 在 Spring MVC 中可以直接⽤⽅法中的参数来实现传单个参&…

uni-app:登录与支付-- 三秒后自动跳转

三秒后自动跳转 三秒后自动跳转到登录页面 需求描述:在购物车页面,当用户点击 “结算” 按钮时,如果用户没有登录,则 3 秒后自动跳转到登录页面 在 my-settle 组件的 methods 节点中,声明一个叫做 showTips 的方法&am…

Vue:生命周期

1、定义 生命周期函数(俗称:钩子函数) 根据vue整个渲染机制,在渲染的每个关键点上,提供对应的函数,进行一些相关的业务操作。 2、四个阶段 初始阶段:beforeCreate():可以加loadi…

vue-qr 生成二维码-使用

1、vue-qr官网说明 vue-qr - npm 2、使用 2.1 安装 vue-qr npm install vue-qr --save 2.2 代码 import vueQr from vue-qr; <el-dialog title"摘要" :visible.sync"openSummary" width"700px" append-to-body> <el-row> <el…

Oracle基础(表空间、用户、授权、表、数据类型、数据导入导出等)

Oracle基础(表空间、用户、授权、表、数据类型、数据导入导出等1 创建表空间1.1 概述1.2 语法&#xff1a;1.3 示例&#xff1a;2 创建用户2.1 语法2.2 示例2.3 用户授权类型3 表的创建、修改、删除3.1 表创建3.1.1 概述3.1.2 语法3.1.3 示例3.1.4 表的数据类型3.2 表修改3.2.1…

Oracle系列之七:表的创建与管理

Oracle表的创建与管理1. 表的创建2. 表的修改3. 表中数据的增删改查4. 表的Merge5. 表的删除6. 表的重命名7. 表的索引8. 表的约束9. dual表表是Oracle数据库中最基础的存储对象&#xff0c;用于存储数据。本文主要介绍了Oracle表的创建与管理&#xff0c;包括表的创建、修改、…

图像处理:双边滤波算法

今天主要是回顾一下双边滤波&#xff0c;我曾经在这篇——图像处理&#xff1a;推导五种滤波算法中推导过它&#xff0c;其中包含了我自己写的草稿图。 目录 双边滤波算法原理 &#xff08;1&#xff09;空间域核 &#xff08;2&#xff09;值域核 理解双边滤波 空域权重​…

Reactor模型在库存指令模块中的运用

Reactor是一种高性能网络模型&#xff0c;在netty、redis、nginx、kafaka、memcached等重要组件&#xff0c;以及唯品会自研的OSP框架都有应用&#xff0c;Reactor模型在提升性能和解耦方面都做得非常好&#xff0c;其编程思想也可以运用到业务系统的开发当中&#xff0c;本文主…

VUE:常见的面试题和答案

1. Vue组件的生命周期有哪些&#xff0c;它们的执行顺序是什么? 答&#xff1a;Vue组件的生命周期包括beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy和destroyed等。它们的执行顺序如下&#xff1a; beforeCreate -> created ->…

21从零开始学Java之while与do-while循环的用法有什么不同?

作者&#xff1a;孙玉昌&#xff0c;昵称【一一哥】&#xff0c;另外【壹壹哥】也是我哦 千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者 前言 在上一篇文章中&#xff0c;壹哥给大家讲解了循环的概念&#xff0c;并重点给大家讲解了for循环的使用…

腾讯轻联流程运行错误如何排查问题?

我们在使用腾讯轻联时&#xff0c;会发现有些流程并没有运行成功&#xff0c;例如我们希望数据可以及时同步到腾讯文档&#xff0c;流程也有执行&#xff0c;但是却执行失败了&#xff0c;那么如何排查问题呢&#xff1f; 其中有几类常见问题 1. 流程不运行的问题请查看&…

【WCH】基于STM32F1标准库程序烧录到CH32F203中运行方法

【WCH】基于STM32标准库程序烧录到CH32F203中运行方法&#x1f4cc;相关篇《关于CH32F203程序下载方式说明》 ✨看到CH32F203手册上写的该芯片也是ARM Cortex-M3内核&#xff0c;那么上层代码应该也是兼容的&#xff0c;为例证实这一点&#xff0c;开干&#xff0c;先来一个简单…

C++---状态机模型---大盗阿福(每日一道算法2023.4.11)

注意事项&#xff1a; 建议先了解状态机的基本定义&#xff1a;状态机-百度百科。 题目&#xff1a; 阿福是一名经验丰富的大盗。趁着月黑风高&#xff0c;阿福打算今晚洗劫一条街上的店铺。 这条街上一共有 N 家店铺&#xff0c;每家店中都有一些现金。 阿福事先调查得知&…

实验手册 - 第8周DataFrame API/Spark SQL

目录标题实验1实验内容绘制散点图将数据保存到MySQL# import os # os.getcwd() import findspark findspark.init() from pyspark.sql import SparkSessionspark SparkSession.builder.getOrCreate()实验1 实验内容 通过DataFrame API或者Spark SQL对数据源进行修改列类型、…

malloc hook进行内存泄漏检测

记录下使用malloc的hook形式&#xff0c;写个小的demo&#xff0c;并记录遇到的问题 1. 实现代码&#xff1a; CMakeLists.txt和相应的memory_leak.cpp文件 cmake_minimum_required(VERSION 3.14) project(demo)set(_SRCmemory_leak.cpp)add_library(memory_leak SHARED ${_S…