Linux学习第18天:Linux并发与竞争: 没有规矩不成方圆

Linux版本号4.1.15   芯片I.MX6ULL                                    大叔学Linux    品人间百味  思文短情长


        提到锁”,可能想到的更多的是限制。现实中,生活中锁也 存在于身边的方方面面。正所谓没有规矩不成方圆, 没有身边的这些锁,这些限制,社会将会变得无序、混乱。为了规范这些无序和混乱,就得根据实际情况制定规则制度甚至法律来进行束缚和限制。正如本篇笔记要讲解的内容一样,Linux内核采用一定的方式方法(函数)制定了这些所谓的规则,才能使程序变得更流畅。

        本篇笔记主要学习Linux处理并发与竞争的机制。主要内容包括原子操作、自旋锁、信号量和互斥体。

一、并发与竞争

1.简介

        Linux是多任务操作系统,存在多个任务同时访问同一内存区域,造成这些任务会相互覆盖这段内存中的数据,从而造成内存数据的混乱。多个线程同时操作临界区就会发生竞争(竞争)并发导致。

2.保护什么

        保护共享资源(数据)。

二、原子操作

1.简介

        原子操作就是指不能再进一步分割的操作,用于变量和位操作。

2.原子整形操作API函数

原子整形操作API函数
函数描述
ATOMIC_INIT(init i)定义原子变量的时候对其进行初始化。
int atomic_read(atomic_t *v)读取v的值,并返回。
void atomic_set(atomic_t *v,int i)向v写入i值。
void atomic_add(atomic_t *v)给v加上i值。
void atomic_sub(atomic_t *v)给v减去i值。
void atomic_inc(atomic_t *v)自增
void atomic_dec(atomic_t *v)自减
void atomic_inc_return(atomic_t *v)自增并返回v值
void atomic_dec_return(atomic_t *v)自减并返回v值
int atomic_sub_and_test(int i,atomic_t *v)从v减i,如果结果为0就返回真,否则返回为假
int atomic_dec_and_test(int i,atomic_t *v)从v减1,如果结果为0就返回真,否则返回为假
int atomic_add_and_test(int i,atomic_t *v)从v加i,如果结果为0就返回真,否则返回为假
int atomic_inc_and_test(int i,atomic_t *v)从v加1,如果结果为0就返回真,否则返回为假

3.原子位操作API函数

原子位操作API函数
函数描述
void set_bit(int nr,void *p)将p地址的第nr位置1
void clear_bit(int nr,void *p)将p地址的第nr位清零
void change_bit(int nr,void *p)将p地址的第nr位翻转
int test_bit(int nr,void *p)获取p地址的第nr位的值
int test_and_set(int nr,void *p)将p地址的nr位置1,并返回nr位原来的值
int test_and_clear(int nr,void *p)将p地址的nr位清零,并返回nr位原来的值
int  test_and_change(int nr,void *p)将p地址的第nr位翻转,并返回nr位原来的值

三、自旋锁

1.简介

        当一个线程要访问某个共享资源的时候首先要先获取相应的锁,锁只能被一个线程持有,只要此线程不释放拥有的锁,那么其他的线程就不能获取此锁。

        自旋---原地打转

        缺点:时间短。

        使用结构体spinlock_t表示自旋锁。

2.自旋锁API函数

自旋锁API函数
函数描述
DEFINE_SPINLOCK(spinlock_t lock)定义并初始化一个自选变量
int spin_lock_init(spinlock_t *lock)初始化自旋锁

void spin_lock(spinlock_t *lock)

获取指定的自旋锁,加锁
void spin_unlock(spinlock_t *lock)释放指定的自旋锁
int spin_trylock(spinlock_t *lock)尝试获取指定的自旋锁,如果没有获取就返回0
int spin_is_locked(spinlock_t *lock)

检查指定的自旋锁是否被获取,如果没有被获取就返回非0,否则返回0

        自旋锁适用于线程与线程之间,被自旋锁保护的临界区一定不能调用任何能引起睡眠和阻塞的API函数,否则会导致死锁的发生。

        自旋锁会自动禁止抢占。

        中断里面可以使用自旋锁,但在中断里面使用自旋锁的时候,在获取之前一定要先禁止本地中断。相应的API函数如下:

函数描述
void spin_lock_irqsave(spinlock_t *lock,unsigned long flags)保存中断状态,禁止本地中断,并获取自旋锁。
void spin_unlock_irqrestore(spinlock_t *lock,unsigned long flags)将中断状态恢复打以前状态,并且激活本地中断,释放自旋锁。

        下半部也会竞争共享资源,下半部使用自旋锁的API函数有:

函数       描述
void spin_lock_bh(spinlock_t *lock)关闭下半部,并获取自旋锁
void spin_unlock_bh(spinlock_t lock)打开下半部,并释放自旋锁

3.其他类型的锁

        实际应用中用的不多,多的是在Linux内核中使用。

1)、读写自旋锁

2)、顺序锁

4.使用注意事项

1)、持有时间不能太长

2)、自旋锁保护的临界区内部能调用任何可能导致线程休眠的API函数,否则可能会导致死锁。

3)、不能递归申请自旋锁

4)、多核SOC编写程序

四、信号量

1.简介

        信号量常用于对共享资源的访问。

        信号量可以使线程进入休眠状态。

        信号量的开销比自旋锁要大。

        信号量特点:

1)、适用于占用资源比较长的场所。

2)、不能用于中断中。

        通过信号量控制访问资源的线程数。

        不能用于互斥访问。

2.信号量API函数

        使用semaphore结构体表示信号量。相关的API函数如下:

函数描述
DEFINE_SEMAPHORE(name)定义一个信号量,并设置信号量的值为1
void sema_init(struct semaphore *sem,int val)初始化信号量sem,设置信号量的值为val.
void down(struct semaphore *sem)获取信号量,不能用在中断中使用
int down_trylock(struct semaphore *sem)尝试获取信号量,能获取就返回0.如果不能返回非0,并且不会进入休眠。
int down_interruptible(struct semaphore *sem)获取信号量,进入休眠以后是可以被信号打断的。
void up(struct semaphore *sem)释放信号量

五、互斥体

1.简介

        一次只有一个线程访问共享资源,不能递归申请。需要互斥访问的时候建议使用mutex.

        注意以下几点:

1)、不能在中断中使用。

2)、保护的临界区可以调用引起阻塞的API函数。

3)、必须由mutex的持有者释放mutex。mutex不能递归上锁和解锁。

2.互斥体API函数

        相关的API函数有:

函数描述
DEFINE_MUXTEX(name)定义并初始化一个mutex变量
void mutex_init(mutex *lock)初始化mutex
void mutex_lock(struct mutex *lock)获取mutex  上锁  获取不到就休眠
void mutex_unlock(struct mutex *lock)释放mutex  解锁
iint mutex_trylock(struct mutex *lock)尝试获取mutex 成功返回0 失败返回0
int mutex_is_locked(struct mutex *lock)判断mutex是否被获取 获取返回1 否则返回0
int mutex_lock_interruptible(struct mutex *lock)使用此函数获取信号量失败进入休眠以后可以被信号打断

六、总结

        本篇笔记主要学习了相关的概念及API函数,并没有相关的案例进行说明。案例将在下一篇笔记中给出。本篇笔记主要内容包括原子操作、自旋锁、信号量和互斥体。

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

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

相关文章

webpack 基础配置

常见配置 文件打包的出口和入口webpack如何开启一台服务webpack 如何打包图片,静态资源等。webpack 配置 loader配置 plugin配置sourceMap配置 babel 语法降级等 接下来 , 我们先从webpack的基本配置 开始吧! 在准备 配置之前 , 搭建一个 …

【窗体】Winform两个窗体之间通过委托事件进行值传递,基础篇

2023年,第38周。给自己一个目标,然后坚持总会有收货,不信你试试! 在实际项目中,我们可能会用到一些窗体做一些小工具或者小功能。比如:运行程序,在主窗体A基础上,点击某个按钮希望能…

修改mars3d地球背景色

示例链接 示例链接 修改代码

Git: 工作区、暂存区、本地仓库、远程仓库

参考链接: Git: 工作区、暂存区、本地仓库、远程仓库 https://blog.csdn.net/weixin_36750623/article/details/96189838

《C++ primer plus》精炼(OOP部分)——对象和类(5)

“学习是照亮心灵的火炬,它永不熄灭,永不止息。” 文章目录 类的自动和强制类型转换原始类型转换为自定义类型将自定义类型转换为原始类型 类的自动和强制类型转换 原始类型转换为自定义类型 可以用一个参数的构造函数来实现,例如&#xff…

QStandardItem通过setCheckable添加复选框后无法再次通过setCheckable取消复选框的问题

前言 如题所示&#xff0c;通过setCheckable添加复选框后&#xff0c;想要通过setCheckable(false)取消复选框&#xff0c;你会发现根本没有作用的。 问题复现 #include "widget.h" #include "ui_widget.h" #include <QList>Widget::Widget(QWidg…

卡尔曼滤波(Kalman Filter)原理浅析-数学理论推导-1

目录 前言数学理论推导1. 递归算法2. 数学基础结语参考 前言 最近项目需求涉及到目标跟踪部分&#xff0c;准备从 DeepSORT 多目标跟踪算法入手。DeepSORT 中涉及的内容有点多&#xff0c;以前也就对其进行了简单的了解&#xff0c;但是真正去做发现总是存在这样或者那样的困惑…

Java idea编译器工程out目录修改

问题 多个工程在一个文件夹下&#xff0c;有时会变为所有的工程只用一个out文件夹&#xff0c;这时运行会出错。 解决方案是将各自的工程out放在自己的文件夹下面 以上面这个工程为例 如果project structure里面有则直接按照下面的指标设置&#xff0c;如果没有则添加到里面再…

ABB 1TGE120010R1300 控制主板模块

ABB 1TGE120010R1300 控制主板模块是一种用于控制和监测电力设备的模块&#xff0c;具有以下功能&#xff1a; 控制和监测电力设备&#xff1a;该模块可以通过与电力设备连接来控制和监测设备的性能和状态&#xff0c;例如启停设备、调节电压和功率等。 通信功能&#xff1a;该…

docker 和k8s 入门

docker 和k8s 入门 本文是云原生的学习记录&#xff0c;可以参考以下文档 k8s https://www.yuque.com/leifengyang/oncloud 相关视频教程可参考如下 https://www.bilibili.com/video/BV13Q4y1C7hS?p2&vd_source0882f549dac54045384d4a921596e234 相对于公有云&#x…

【力扣周赛】第 362 场周赛(⭐差分匹配状态压缩DP矩阵快速幂优化DPKMP)

文章目录 竞赛链接Q1&#xff1a;2848. 与车相交的点解法1——排序后枚举解法2——差分数组⭐差分数组相关题目列表&#x1f4d5;1094. 拼车1109. 航班预订统计2381. 字母移位 II2406. 将区间分为最少组数解法1——排序贪心优先队列解法2——差分数组 2772. 使数组中的所有元素…

TCP IP网络编程(五) 基于TCP的服务器端、客户端 (补充)

文章目录 回声客户端的完美实现回声客户端出现的问题回声客户端问题解决方法 TCP原理TCP套接字中的I/O缓冲TCP内部工作原理1&#xff1a;与对方套接字的连接TCP内部工作原理2&#xff1a;与对方主机的数据交换TCP内部工作原理3&#xff1a;断开与套接字的连接 回声客户端的完美…

双向链表的实现(增删查改)——最好理解的链表

双向链表的实现 一&#xff0c;双向链表的特点二&#xff0c;双向链表的结构三&#xff0c;双向链表的内容实现3.1创建node节点3.2初始化3.3打印3.4插入3.4.1尾插3.4.2头插3.4.3在pos位置上插入 3.5删除3.5.1尾删3.5.2头删3.5.3删除pos位置上的数据 四&#xff0c;调试技巧&…

day21算法

常见的七种查找算法&#xff1a; ​ 数据结构是数据存储的方式&#xff0c;算法是数据计算的方式。所以在开发中&#xff0c;算法和数据结构息息相关。今天的讲义中会涉及部分数据结构的专业名词&#xff0c;如果各位铁粉有疑惑&#xff0c;可以先看一下哥们后面录制的数据结构…

【C++学习】继承

目录 一、继承的概念及定义 1、继承的概念 2、继承的定义 2.1 定义格式 2.2 继承关系和访问限定符 2.3 继承基类成员访问方式的变化 二、基类和派生类对象赋值转换 三、继承中的作用域 四、派生类的默认成员函数 五、继承与友元 六、继承与静态成员 七、复杂的菱形…

SpringMvc第五战-【SpringMvcJSR303和拦截器】

前言&#xff1a; 小编阐述了springmvc 中的文件下载&#xff0c;以及jrebel的使用和文件下载以及多文件下载! 在本次小编将会介绍JSR303的概念&#xff0c;应用场景和在具体实例的使用&#xff1b;和拦截器的应用 一.JSR303的介绍 1.什么是JSR303&#xff1f; JSR是Java S…

Aztec的隐私抽象:在尊重EVM合约开发习惯的情况下实现智能合约隐私

1. 引言 Aztec的架构&#xff0c;不同于当前“通过EVM兼容执行环境”所实现的区块链水平扩容趋势。Aztec内部笑称其构建的为首个非zkEVM协议。 Aztec专注于实现&#xff1a; 成为理解和需要智能合约隐私的开发者的终极解决方案。 Aztec为开发者提供构建隐私优先app所需的网…

【微信小程序开发】宠物预约医疗项目实战-环境配置与Vant UI集成

第一章 宠物预约医疗项目实战-环境配置与Vant UI集成 文章目录 前言一、Vant UI是什么&#xff1f;二、使用步骤2.1 安装 node.js2.2 通过 npm 安装vant2.3 修改 app.json2.4 修改 project.config.json2.5 构建 npm 包2.6 使用组件全局引入和局部引入全局引入局部引入 前言 Va…

基于Java+SpringBoot+Vue+uniapp点餐小程序(亮点:协同过滤算法、会员系统,购物车结算、在线聊天)

校园点餐小程序 一、前言二、我的优势2.1 自己的网站2.2 自己的小程序&#xff08;小蔡coding&#xff09;2.3 有保障的售后2.4 福利 三、开发环境与技术3.1 MySQL数据库3.2 Vue前端技术3.3 Spring Boot框架3.4 微信小程序 四、功能设计4.1 系统功能结构设计4.2 主要功能描述 五…

SpringBoot整合Flowable

1. 配置 &#xff08;1&#xff09; 引入maven依赖 <dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>6.7.2</version></dependency><!-- MySQL连接 -->&l…