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

嵌入式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函数为例,代码如下:
在这里插入图片描述

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

相关文章:

嵌入式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…...

EasyExcel的源码流程(导入Excel)

1. 入口 2. EasyExcel类继承了EasyExcelFactory类,EasyExcel自动拥有EasyExcelFactory父类的所有方法,如read(),readSheet(),write(),writerSheet()等等。 3. 进入.read()方法,需要传入三个参数(文件路径…...

基于 jasypt 实现spring boot 配置文件脱敏

前言 在项目构建过程中,保护敏感信息的安全性至关重要,为了提高系统的安全性能,我们采用了Jasypt来对配置文件中的敏感信息进行加密处理,以确保系统的机密信息不被轻易泄露。 步骤 添加Maven依赖 首先,我们需要添加…...

Python——ASCII编码与Unicode(UTF-8,UTF-16 和 UTF-32)编码

Python3 Python——ASCII编码与Unicode(UTF-8,UTF-16 和 UTF-32)编码 文章目录 Python3一、编码与编码格式二、ASCII编码与UTF-8编码(UTF-16 和 UTF-32编码)三、ASCII 字符串和 Unicode 字符串 最近看Python程序的文件…...

【多媒体技术与实践】音频信息获取和处理——编程题汇总

1:音频信息数据量计算 已知采样频率(单位KHz)、量化位数、声道数及持续时间(单位分钟),求未压缩时的数据量(单位MB). 例如: 输入: 22.05 16 2 3 &#xff…...

堆优化迪氏最短单源路径原理及C++实现

时间复杂度 O(ElogE),E是边数。适用与稀疏图。 使用前提 边的权为正。可以非连通,非连通的距离为-1。 原理 优选队列(小根堆)记录两个数据:当前点到源点距离,当前点。先处理距离小的点;如果…...

Leetcode202. 快乐数

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为: 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0…...

【MySQL】MySql常见面试题总结

目录 一、什么是sql注入 二、sql语句的执行流程 三、内连接和外连接的区别 四、Union和Union All 有什么区别 五、MySql如何取差集 六、DELETE和TRUNCATE有什么区别 七、count(*)和count(1)的区别 八、MyISAM和InnoDB的区…...

【Java 进阶篇】JDBC PreparedStatement 详解

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

嵌入式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 失败…...

【计算机网络】 基于UDP的简单通讯(客户端)

文章目录 客户端流程代码实现添加头文件以及库依赖加载库创建套接字发送接收数据关闭套接字、卸载库 测试 客户端 流程 客户端跟服务端差不多,也要先加载库,在加载库之后也要创建套接字,但是客户端一定是没有绑定ip地址的,之后是…...

【云备份项目】:环境搭建(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…...

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

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

JavaScript内置对象 - Array数组(四)- 序列生成器

序列生成器是生成一个指定起始值和结束值的序列,并且根据指定间隔长度,生成序列数组。 完成此功能需要使用到Array内置对象的from()对象,以及类数组相关知识,前面几篇有相关案例进行演示。 地址一:JavaScript内置对象…...

GD32F103x IIC通信

1. IIC通信 1.IIC的介绍 IIC总线有两条串行线,其一是时钟线SCK(同步),其二是数据线SDA。只有一条数据线属于半双工。应用中,单片机常常作为主机,外围器件可以挂载多个。(当然主机也可以有多个。…...

什么是FOSS

FOSS 是指 自由和开放源码软件(Free and Open Source Software)。这并不意味着软件是免费的。它意味着软件的源代码是开放的,任何人都可以自由使用、研究和修改代码。这个原则允许人们像一个社区一样为软件的开发和改进做出贡献。...

C++语言GDAL批量裁剪多波段栅格图像:基于像元个数裁剪

本文介绍基于C 语言的GDAL模块,按照给定的像元行数与列数,批量裁剪大量多波段栅格遥感影像文件,并将所得到的裁剪后新的多波段遥感影像文件保存在指定路径中的方法。 在之前的文章中,我们多次介绍了在不同平台,或基于不…...

简单丝的tab切换栏(html/CSS)

#html <!DOCTYPE html> <html lang"en" > <head><meta charset"UTF-8"><title>CSS实现左右滑动选项卡效果</title><link rel"stylesheet" href"https://cdnjs.cloudflare.com/ajax/libs/meyer-res…...

LabVIEW开发带式谱感测技术

LabVIEW开发带式谱感测技术 如今&#xff0c;通过无线网络传输的数据量正在迅速增加&#xff0c;并导致频谱稀缺。超过数十亿的无线设备将被连接起来&#xff0c;并需要互联网接入。因此&#xff0c;无线电频谱管理方案的效率不足以授予对所有设备的访问权限。在频谱分配中&am…...

认识柔性数组

在C99中&#xff0c;结构中的最后一个元素允许是未知大小的数组&#xff0c;这就叫做柔性数组成员 限制条件是&#xff1a; 结构体中最后一个成员未知大小的数组 1.柔性数组的形式 那么我们怎样写一个柔性数组呢 typedef struct st_type {int i;int a[0];//柔性数组成员 }ty…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...