嵌入式Linux应用开发-驱动大全-第一章同步与互斥②

news2025/1/11 0:04:02

嵌入式Linux应用开发-驱动大全-第一章同步与互斥②

  • 第一章 同步与互斥②
    • 1.3 原子操作的实现原理与使用
      • 1.3.1 原子变量的内核操作函数
      • 1.3.2 原子变量的内核实现
        • 1.3.2.1 ATOMIC_OP在 UP系统中的实现
        • 1.3.2.2 ATOMIC_OP在 SMP系统中的实现
      • 1.3.3 原子变量使用案例
      • 1.3.4 原子位介绍
        • 1.3.4.1 原子位的内核操作函数

第一章 同步与互斥②

在这里插入图片描述

1.3 原子操作的实现原理与使用

在上面的第 2个失败例子里,问题在于对 valid变量的修改被打断了。如果对 valid变量的操作不能被打断,就解决这个问题了。
这可以使用原子操作,所谓“原子操作”就是这个操作不会被打断。Linux有 2种原子操作:原子变量、原子位。

1.3.1 原子变量的内核操作函数

原子变量的操作函数在 Linux内核文件 arch\arm\include\asm\atomic.h中。
原子变量类型如下,实际上就是一个结构体(内核文件 include/linux/types.h):
在这里插入图片描述

特殊的地方在于它的操作函数,如下(下表中 v都是 atomic_t指针):
在这里插入图片描述

1.3.2 原子变量的内核实现

注意:SMP就是 Symmetric Multi-Processors,对称多处理器;UP即 Uni-Processor,系统只有一个单核 CPU。
这些函数都是在 Linux内核文件 arch\arm\include\asm\atomic.h中。
atomic_read,atomic_set这些操作都只需要一条汇编指令,所以它们本身就是不可打断的。
问题在于 atomic_inc这类操作,要读出、修改、写回。
以 atomic_inc为例,在 atomic.h文件中,如下定义:

#define atomic_inc(v)  atomic_add(1, v) 

atomic_add又是怎样实现的呢?用下面这个宏:

ATOMIC_OPS(add, +=, add) 

把这个宏展开:

#define ATOMIC_OPS(op, c_op, asm_op)   \
 ATOMIC_OP(op, c_op, asm_op)     \
 ATOMIC_OP_RETURN(op, c_op, asm_op)   \
 ATOMIC_FETCH_OP(op, c_op, asm_op) 

从上面的宏可以知道,一个 ATOMIC_OPS定义了 3个函数。比如“ATOMIC_OPS(add, +=, add)”就定义了这 3个函数:

atomic_add 
atomic_add_return 
atomic_atomic_fetch_add 或 atomic_fetch_add_relaxed 

我们以 ATOMIC_OP(add, +=, add)为例,看它是如何实现 atomic_add函数的,对于 UP系统、SMP系统,分别有不同的实现方法。

1.3.2.1 ATOMIC_OP在 UP系统中的实现

对于 ARMv6以下的 CPU系统,不支持 SMP。原子变量的操作简单粗暴:关中断,中断都关了,谁能来打断我?代码如下(arch\arm\include\asm\atomic.h):
在这里插入图片描述

1.3.2.2 ATOMIC_OP在 SMP系统中的实现

对于 ARMv6及以上的 CPU,有一些特殊的汇编指令来实现原子操作,不再需要关中断,代码如下(arch\arm\include\asm\atomic.h):
在这里插入图片描述

在 ARMv6及以上的架构中,有 ldrex、strex指令,ex表示 exclude,意为独占地。这 2条指令要配合使用,举例如下:
① 读出:ldrex r0, [r1]
读取 r1所指内存的数据,存入 r0;并且标记r1所指内存为“独占访问”。
如果有其他程序再次执行“ldrex r0, [r1]”,一样会成功,一样会标记 r1所指内存为“独占访问”。 ② 修改 r0的值
③ 写入:strex r2, r0, [r1]:
如果 r1的“独占访问”标记还存在,则把 r0的新值写入 r1所指内存,并且清除“独占访问”的标记,把 r2设为 0表示成功。
如果 r1的“独占访问”标记不存在了,就不会更新内存,并且把 r2设为 1表示失败。
假设这样的抢占场景:
① 程序 A在读出、修改某个变量时,被程序 B抢占了;
② 程序 B先完成了操作,程序 B的 strex操作会清除“独占访问”的标记;
③ 轮到程序 A执行剩下的写入操作时,它发现独占访问”标记不存在了,于是取消写入操作。 这就避免了这样的事情发生:程序 A、B同时修改这个变量,并且都自认为成功了。
举报个例子,比如 atomic_dec,假设一开始变量值为 1,程序 A本想把值从 1变为 0;但是中途被程序B先把值从 1变成 0了;但是没关系,程序 A里会再次读出新值、修改、写入,最终这个值被程序 A从 0改为-1。
在 ARMv6及以上的架构中,原子操作不再需要关闭中断,关中断的花销太大了。并且关中断并不适合SMP多 CPU系统,你关了 CPU0的中断,CPU1也可能会来执行些操作啊。
在 ARMv6及以上的架构中,原子操作的执行过程是可以被打断的,但是它的效果符合“原子”的定义:一个完整的“读、修改、写入”原子的,不会被别的程序打断。它的思路很简单:如果被别的程序打断了,那就重来,最后总会成功的。

1.3.3 原子变量使用案例

现在可以使用原子变量实现:只能有一个 APP访问驱动程序。代码如下:

01 static atomic_t valid = ATOMIC_INIT(1); 
02 
03 static ssize_t gpio_key_drv_open (struct inode *node, struct file *file) 04 { 
05      if (atomic_dec_and_test(&valid)) 
06      { 
07              return 0; 
08      } 
09      atomic_inc(&valid); 
10      return -EBUSY; 
11 } 
12 
13 static int gpio_key_drv_close (struct inode *node, struct file *file) 
14 { 
15      atomic_inc(&valid); 
16      return 0; 
17 } 
18 

第 5行的 atomic_dec_and_test,这是一个原子操作,在 ARMv6以下的 CPU架构中,这个函数是在关中断的情况下执行的,它确实是“原子的”,执行过程不被打断。
但是在 ARMv6及以上的 CPU架构中,这个函数其实是可以被打断的,但是它实现了原子操作的效果,如下图所示:
在这里插入图片描述

1.3.4 原子位介绍

1.3.4.1 原子位的内核操作函数

能操作原子变量,再去操作其中的某一位,不是挺简单的嘛?不过不需要我们自己去实现,内核做好了。
原子位的操作函数在 Linux内核文件 arch\arm\include\asm\bitops.h中,下表中 p是一个 unsigned long指针。
在这里插入图片描述

1.3.4.2 原子位的内核实现
在 ARMv6以下的架构里,不支持 SMP系统,原子位的操作函数也是简单粗暴:关中断。以 set_bit函数为例,代码在内核文件 arch\arm\include\asm\bitops.h中,如下
在这里插入图片描述

在 ARMv6及以上的架构中,不需要关中断,有 ldrex、strex等指令,这些指令的作用在前面介绍过。还是以 set_bit函数为例,代码如下:
在这里插入图片描述

我不再使用原子位操作来写代码,留给你们练习吧。

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

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

相关文章

js正则的前瞻释义

/^(?a)aa$/可以匹配aa,但不能匹配aaa,因为前瞻不消耗字符串 检验密码强度的正则 /^(?.*[a-z])(?.*[A-Z])(?.*\d)(?.*[$,_.])[a-zA-Z\d$,_.]{6,12}$/var reg/^(?.*[a-z])(?.*[A-Z])(?.*\d)(?.*[$,_.])[a-zA-Z\d$,_.]{6,12}$/var res reg.test(abcdefg.A6)console.log(…

SpringBoot中使用Servlet和Filter

为什么要把Servlet和Filter写在一起,因为使用方式很相似 两种方式 第一种,使用Servlet和Filter 使用Servlet 继承HttpServlet 注册Servlet 使用Filter 1.自定义过滤器 2.注册过滤器 这里注意一点 使用/**无效 至少我这2.4.5版本是这样 过滤所有请求用/* 那么其实还有…

CodeCraft-21 and Codeforces Round 711 (Div. 2)A-F

1.Problem - A - Codeforces (1)题意 求一个大于等于n的整数x,满足gcd(x,sum(dig(x)) > 1,dig表示x的各个数位。 (2)思路 考虑最差是满足gcd(x,sum(dig(x)) 2,因此不会枚举很多,直接暴力枚…

【Diffusion】DDPM - (2)公式推导 之 前向扩散

1、加噪过程 1、将 图像 x 0 x_0 x0​ 像素值映射到 [-1, 1] 之间 x 255 2 − 1 , w h e r e    x 为图像中的像素值 \quad \frac{x}{255} \times 2-1, \quad where \; x 为图像中的像素值 255x​2−1,wherex为图像中的像素值 \quad 2、生成一张尺寸相同的噪声图片,像…

【Kafka专题】Kafka收发消息核心参数详解

目录 前置知识课程内容一、从基础的客户端说起(Java代码集成使用)1.1 消息发送者源码示例1.2 消息消费者源码示例1.3 客户端使用小总结 *二、从客户端属性来梳理客户端工作机制*2.1 消费者分组消费机制2.2 生产者拦截器机制2.3 消息序列化机制2.4 消息分…

二叉搜索树 , Set 和 Map (JAVA)

二叉搜索树 二叉搜索树又称二叉排序树,它具有以下性质的二叉树或空树: 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值若它的右子树不为空,则右子树上所有节点的值都大于根节点的值它的每颗子树也分别为二叉搜索树 二叉搜索树的…

北京开发APP需要多少钱

北京开发一个移动应用(APP)的费用因多种因素而异,包括项目的规模、复杂性、所需功能、设计要求、技术选择、开发团队的经验和地理位置等。一般来说,北京的APP开发费用通常较高,因为这是中国的主要技术和创新中心之一&a…

【云备份项目】:环境搭建(g++、json库、bundle库、httplib库)

文章目录 1. g 升级到 7.3 版本2. 安装 jsoncpp 库3. 下载 bundle 数据压缩库4. 下载 httplib 库从 Win 传输文件到 Linux解压缩 1. g 升级到 7.3 版本 🔗链接跳转 2. 安装 jsoncpp 库 🔗链接跳转 3. 下载 bundle 数据压缩库 安装 git 工具 sudo yum…

嵌入式Linux应用开发-驱动大全-第一章同步与互斥①

嵌入式Linux应用开发-驱动大全-第一章同步与互斥① 第一章 同步与互斥①1.1 内联汇编1.1.1 C语言实现加法1.1.2 使用汇编函数实现加法1.1.3 内联汇编语法1.1.4 编写内联汇编实现加法1.1.5 earlyclobber的例子 1.2 同步与互斥的失败例子1.2.1 失败例子11.2.2 失败例子21.2.3 失败…

IDEA中的神仙插件——Smart Input (自动切换输入法)

推荐专栏:开发环境配置攻略 致力于记录学习过程中各种软件的安装及环境配置操作,并提供详细的步骤说明和丰富的配图。涵盖了 Java、Python、IntelliJ IDEA、Tomcat、MySQL 等常见开发工具和服务器组件的配置,为初学者提供一个实用、全面的配置…

Sentinel-2波段合成

Sentinel-2波段合成 在上一篇博客中下载了Sentinel-2数据,他有13个波段的.jp2文件,下面选取需要使用的波段进行合成。 导入了B2(蓝色)、B3(绿色)、B4(红色)、B8(近红外&…

第一章 概论

第一章 概论 引言基本概念和术语数据、数据元素和数据项数据的逻辑结构数据的存储结构(物理结构)运算 算法及描述算法分析时间复杂度空间复杂度 牛刀小试 引言 数据结构是指一组相互之间存在一种或多种特定关系的数据的组织方式和它们在计算机内的存储方…

【Java 进阶篇】JDBC PreparedStatement 详解

在Java中,与关系型数据库进行交互是非常常见的任务之一。JDBC(Java Database Connectivity)是Java平台的一个标准API,用于连接和操作各种关系型数据库。其中,PreparedStatement 是 JDBC 中一个重要的接口,用…

ARM---实现1-100求和任务

.text .globl _start_start:mov r0, #0x1mov r1, #0x1 给r1加一固定1不变mov r2, #0x64 100判断bl sumcmp r1, r2 sum:addcc r1, r1,#0x1 r1自增addcc r0, r0, r1 r0求和movcc pc,lrstop:b stop.end

Linux shell编程学习笔记6:查看和设置变量的常用命令

上节我们介绍了变量的变量命名规则、变量类型、使用变量时要注意的事项,今天我们学习一下查看和设置变量的一些常用命令,包括变量的提升,有些命令在之前的实例中已经使用过了。 一、 echo :查看变量的值 语法格式:ech…

金融机构操作风险与内控合规的介绍

目录 一.前言 术语 二.功能设计 三.部分功能简介 流程管理 流程清单 流程详情 流程重检 流程重检反馈 风险与控制自我评估(RCSA) 评估计划管理 评估结果管理 关键风险指标(KRI) 指标库管理 基础数据项录入 指标监测…

电阻的基础与应用

文章目录 电阻的基础与应用电阻的介绍与分类电阻介绍电阻的分类碳膜/金属膜电阻厚膜/薄膜电阻功能性电阻(光敏/热敏/压敏)特殊电阻(绕线电阻/水泥电阻/铝壳电阻) 电阻的主要厂家与介绍国外厂家VISHAY(威世)KOA(兴亚)Kyocera(京瓷)…

电脑右键新建记事本不见了--设置恢复篇(无需操作注册表)

电脑右键新建记事本不见了–设置恢复篇(无需修改注册表) 电脑不知怎么想右键新建记事本结果竟然不见了,搜寻网上的都是什么修改注册表,粘贴代码修复(感觉太复杂了),这里介绍通过设置内重新对记…

❋JQuery的快速入门 1 了解jq

目录 选定元素 1. jquery基本选择器 2. 层级选择器 3. 元素精确定位 4. 内容选择器 5. 属性选择器及其他 元素解析 操作元素内容与样式 操作文档的文本结构 jq事件 jq动画 JQuery 是一个“写的更少,但做的更多”的轻量级 JavaScript 库。 使用前要先导入…

自定义实现hashmap-python

前文 ​ 今天这篇文章给大家讲讲hashmap,这个号称是所有前后端工程师都会的数据结构。 hashmap基本结构 ​ hashmap这个数据结构其实并不难,它的结构非常清楚,说白了就是一个定长的链表,这个数组的每一个元素都是一个链表。我们…