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

嵌入式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.rhkb.cn/news/147701.html

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

相关文章

《Vue.js+Spring Boot全栈开发实战》简介

大家好,我是老卫。 恰逢中秋国庆双节,不想出门看人山,惟愿宅家阅书海! 今天开箱的这本书是《Vue.jsSpring Boot全栈开发实战》。 外观 从书名故名思议,就是基于Vue.jsSpring Boot来实现企业级应用全栈开发。 该书由…

【单片机】16-LCD1602和12864显示器

1.LCD显示器相关背景 1.LCD简介 (1)显示器,常见显示器:电视,电脑 (2)LCD(Liquid Crystal Display),液晶显示器,原理介绍 (3&#xff…

设计模式11、享元模式Flyweight

解释说明:享元模式(Flyweight Pattern)运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。 抽象享元类(Flyweight&…

Spring MVC:数据绑定

Spring MVC 数据绑定数据类型转换数据格式化数据校验 附 数据绑定 数据绑定,指 Web 页面上请求和响应的数据与 Controller 中对应处理方法上的对象绑定(即是将用户提交的表单数据绑定到 Java 对象中)。 过程如下: ServletRequest…

python和java类的编写(属性私有化,方法公开化)

初始化类的属性的2种写法: 如下要注意python对文件名称、类、方法名的命名 方式一:原始的定义 class User1: # 初始化账号和密码 def __init__(self):# 账号和密码self.__username Noneself.__password Nonedef getnsername(self):return self.__us…

服务网关Gateway_入门案例

创建cloud-gateway-gateway9527工程 pom文件引入依赖 <dependencies><!-- 引入网关Gateway依赖 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></depe…

用向量数据库Milvus Cloud搭建检索知识库机器人

检索知识库 Milvus 中已经存储了文本块向量,现在可以进行向量查询了。 以下函数创建了 1 个查询 pipeline。注意,这是本教程中最为关键的一个步骤! ops.ann_search.osschat_milvus(host=MILVUS_HOST, port=MILVUS_PORT, **{metric_type: IP, limit: 3, output_fields: [text…

STM32CubeMX学习笔记-USB接口使用(HID按键)

STM32CubeMX学习笔记-USB接口使用&#xff08;HID按键&#xff09; 一、USB简介1.1 USB HID简介 二、新建工程1. 打开 STM32CubeMX 软件&#xff0c;点击“新建工程”2. 选择 MCU 和封装3. 配置时钟4. 配置调试模式 三、USB3.1 参数配置3.2 引脚配置3.3 配置时钟3.4 USB Device…

【SimpleDateFormat】线程不安全问题分析及解决方案

前言 在日常开发中&#xff0c;我们经常需要去做日期格式转换&#xff0c;可能就会用到SimpleDateFormat类。但是&#xff0c;如果使用不当&#xff0c;就很容易引发生产事故&#xff01; 1. 问题推演 1.1 初始日期工具类 刚开始的日期转换工具类可能长这样&#xff1a; p…

设计模式2、抽象工厂模式 Abstract Factory

解释说明&#xff1a;提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无需指定他们具体的类。 简言之&#xff0c;一个工厂可以提供创建多种相关产品的接口&#xff0c;而无需像工厂方法一样&#xff0c;为每一个产品都提供一个具体工厂 抽象工厂&#xff08;Abstra…

知识图谱02——使用python将信息录入neo4j

将文档传入chatgpt&#xff0c;生成对应的cypher语句 链接: https://pan.baidu.com/s/1Ny-ttbBSpqYEigwYiCWMeA?pwdc7sc 提取码: c7sc 使用命令行安装对应的包 pip install neo4jchatgpt生成出的txt文档中的内容如下&#xff1a; MERGE (Node1:Entity {name: 原始舱单提运单…

Redis BitMap+SpringBoot 实现签到与统计功能

前言&#xff1a; 在各个项目中&#xff0c;我们都可能需要用到签到和 统计功能。签到后会给用户一些礼品以此来吸引用户持续在该平台进行活跃。 签到功能&#xff0c;使用 Redis 中的 BitMap 功能来实现&#xff0c;就是一个非常不错的选择。 一、Redis BitMap 基本用法 Bi…

如何在 Elasticsearch 中使用 Openai Embedding 进行语义搜索

随着强大的 GPT 模型的出现&#xff0c;文本的语义提取得到了改进。 在本文中&#xff0c;我们将使用嵌入向量在文档中进行搜索&#xff0c;而不是使用关键字进行老式搜索。 什么是嵌入 - embedding&#xff1f; 在深度学习术语中&#xff0c;嵌入是文本或图像等内容的数字表示…

nodejs+vue晓海网上订餐系统elementui

管理员功能需求 管理员登陆后&#xff0c;主要模块包括首页、个人中心、用户管理、菜单信息管理等功能。 第三章 系统分析 10 3.1需求分析 10 3.2可行性分析 10 3.2.1技术可行性&#xff1a;技术背景 10 3.2.2经济可行性 11 3.2.3操作可行性&#xff1a; 11 3.3性能分析 11 3.4…

Kubernetes(K8s):容器编排的未来是什么?

文章目录 Kubernetes的核心概念和工作原理1. 节点&#xff08;Nodes&#xff09;2. 容器3. Pod4. 控制器5. 服务 Kubernetes为什么成为容器编排的首选工具&#xff1f;1. 自动化和可扩展性2. 多云支持3. 生态系统和社区4. 云原生开发 未来趋势&#xff1a;K8s如何继续发展和演进…

(三) Markdown插入互联网或本地视频解决方案

前言 不论博客系统是WordPress还是Typecho&#xff0c;绕不开的是两种书写语言&#xff0c;一种称之为富文本&#xff0c;一种叫做Markdown。 Markdown有很多好处&#xff0c;也有很多坏处&#xff0c;比如Markdown本身不具备段落居中的功能&#xff0c;以及Markdown也不具有…

osg实现鼠标框选

目录 1. 需求的提出 2. 具体实现 2.1. 禁止场景跟随鼠标转动 2.2. 矩形框前置绘制 3. 附加说明 3.1. 颜色设置说明 3.2.矩形框显示和隐藏的另一种实现 1. 需求的提出 有时需要在屏幕通过按住键盘上的某个键如Ctrl键且按住鼠标左键&#xff0c;拖出一个矩形&#xff0c;实现框…

Java自学(二)

目录 一、数组逆置&#xff08;临时变量法&#xff09; 二、基本类型和引用类型传参的区别 一、数组逆置&#xff08;临时变量法&#xff09; 二、基本类型和引用类型传参的区别 基本类型传参&#xff0c;形参一般不会改变实参。 形参是实参的一份数据拷贝&#xff0c;改变形…

(unordered)map和set封装(底层红黑树)

map和set封装 文章目录 map和set封装设计问题&#xff08;知其所以然&#xff09;为什么要对iterator进行封装&#xff1f;为什么要引入Self Ref Ptr这些模板参数&#xff1f;为什么是试图从non_const转变为const&#xff0c;而不是const转为non_const如何解决 为什么说能加con…

黑马头条项目环境搭建

注册中心网关配置 spring:cloud:gateway:globalcors:add-to-simple-url-handler-mapping: truecorsConfigurations:[/**]:allowedHeaders: "*"allowedOrigins: "*"allowedMethods:- GET- POST- DELETE- PUT- OPTIONroutes:# 平台管理- id: useruri: lb://…