原子操作

如果共享资源(临界区)非常小,小到只有一个变量的话,就可以不用重量级的加锁- 解锁操作,而是直接使用原子操作。原子操作意味着整个操作的执行过程是原子的,不可中断的。
原子操作分为以下几种,下面一一介绍:

(1)通用原子操作
Linux 内核定义了 32 位的原子变量类型 atomic_t 和 64 位的原子变量类型 atomic64_t,另外还有 atomic_long_t,在 32 位内核中等价于 atomic_t 而在 64 位内 核中等价于 atomic64_t。
其代码如下:

typedef struct { int counter;
} atomic_t;typedef struct { long counter;
} atomic64_t;#if BITS_PER_LONG == 64
typedef atomic64_t atomic_long_t;
#else
typedef atomic_t atomic_long_t;
#endif

32位或者64位原子操作的API主要有以下几种:

/*初始化原子变量的值为 i*/
ATOMIC_INIT(i)/ATOMIC64_INIT(i)/ATOMIC_LONG_INIT(i)/*返回原子变量*v 的值*/
atomic_read(v)/atomic64_read(v)/ atomic_long_read(v):/*给原子变量赋值:将*v 的值设置成 i*/
atomic_set(v, i)/atomic64_set(v, i)/atomic_long_set(v, i):/*给原子变量做加法:*v 的值增加 i*/
atomic_add(i, v)/atomic64_add(i, v)/atomic_long_add(i, v):/*给原子变量做减法:*v 的值减少 i*/
atomic_sub(i, v)/atomic64_sub(i,v)/atomic_long_sub(i, v):/*给原子变量做加法并测试:*v 的值增加 i,若结果为负返回 1,否则为 0*/
atomic_sub_and_test(i, v)/atomic64_sub_and_test(i,v)/atomic_long_sub_and_test(i, v):/*给原子变量做加法并测试:*v 的值增加 i,若结果为负返回 1,否则为 0*/
atomic_add_negtive(i, v)/atomic64_add_negtive(i, v)/atomic_long_add_negtive(i, v):/*给原子变量加一:*v 的值加一*/
atomic_inc(v)/atomic64_inc(v)/atomic_long_inc(v)/*给原子变量减一:*v 的值减一*/
atomic_dec(v)/atomic64_dec(v)/atomic_long_dec(v)/*给原子变量加一并测试:*v 的值加一,若结果为 0 返回 1,否则返回 0*/
atomic_inc_and_test(v)/atomic64_inc_and_test(v)/atomic_long_inc_and_tes t(v)/*给原子变量减一并测试:*v 的值减一,若结果为 0 返回 1,否则返回 0*/
atomic_dec_and_test(v)/atomic64_dec_and_test(v)/atomic_long_dec_and_test(v)/*给原子变量做加法并返回:*v 的值增加 i,返回*v 的新值*/
atomic_add_return(i, v)/atomic64_add_return(i, v)/atomic_long_add_return(i, v)/*给原子变量做减法并返回:*v 的值减少 i,返回*v 的新值*/
atomic_sub_return(i, v)/atomic64_sub_return(i, v)/atomic_long_sub_return(i,v)/*给原子变量加一并返回:*v 的值加一,返回*v 的新值*/
atomic_inc_return(v)/atomic64_inc_return(v)/ atomic_long_inc_return(v)/*给原子变量减一并返回:*v 的值减一,返回*v 的新值*/
atomic_dec_return(v)/atomic64_dec_return(v)/atomic_long_dec_return(v)/*给原子变量做条件加法:如果*v 等于 u 则返回,否则*v 的值增加 i 并返回*v 的新值*/
atomic_add_unless(v, i, u)/atomic_add_unless(v, i, u)/atomic_long_add_unless(v, i, u)/*给原子变量做条件减法:如果*v 大于 i,则*v -= i 并返回*v 的原值*/
atomic_sub_if_positive(i, v)/atomic64_sub_if_positive(i,v)/atomic_long_sub_if_positive(i, v)/*原子变量交换:*v 的值更新为 n,返回*v 的原值*/
atomic_xchg(v, n)/atomic64_xchg(v, n)/atomic_long_xchg(v, n)/*原子变量比较并交换:如果*v 的值等于 o,则*v 的值更新为 n,返回*v 的原值*/
atomic_cmpxchg(v, o, n)/atomic64_cmpxchg(v, o,n)/atomic_long_cmpxchg(v, o, n)

以上相关的代码实现都在内核中的include路径下atomic相关的头文件中以宏定义或者函数的形式实现,这里不再详细的展开介绍。

从 Linux-4.3的内核版本 开始,原子操作引入了各种不同内存有序性的变种版本。以 atomic_set() 为例,现在有四个变种:
(1)严格有序版本:atomic_set(v, i),必须是先执行原子操作以前的访存操作,然后执行原子操作,然后执行原子操作以后的访存操作。相当于原子操作前后都有内存屏障(同时带有 ACQUIRE 和 RELEASE 语义)。
(2)获取有序版本:atomic_set_aquire(v, i),不关心原子操作以前的访存操作,但必须先执行原子操作,然后执行原子操作以后的访存操作。相当于原子操作后面有内存屏障(带有ACQUIRE 语义)。
(3释放有序版本:atomic_set_release(v, i),不关心原子操作以后的访存操作,但必须先执行原子操作以前的访存操作,然后执行执行原子操作。相当于原子操作前面有内存屏障(带有 RELEASE 语义)。
(4)宽松有序版本:atomic_set_relaxed(v, i),完全不关心内存有序性。相当于原子操作前后都没有内存屏障。

(2)本地原子操作

在通用原子变量以外,内核还提供了本地原子变量类型 local_t 和 local64_t。本地原子变量通常是某个 CPU 的本地变量,允许所有的 CPU 读,但是只允许本地 CPU 写。因此本地原子变量不需要内存屏障,性能更好。本地原子变量的主要 API 有:

/*初始化本地原子变量的值为 v*/
LOCAL_INIT(v/LOCAL64_INIT(v)/*返回本地原子变量*v的值*/
local_read(v)/local64_read(v)/*给本地原子变量赋值:将*v的值设置成 i*/
local_set(v, i)/local64_set(v, i)/*给本地原子变量做加法:*v的值增加 i*/
local_add(v, l)/local64_add(v, l)/*给本地原子变量做减法:*v 的值减少 i*/
local_sub(v, l)/local64_sub(v, l) /*给本地原子变量做加法并测试:*v 的值增加 i,若结果为负返回 1,否则为 0*/
local_add_negative(v, l)/local64_add_negative(v, l) /*给本地原子变量做减法并测试:*v 的值减少 i,若结果为 0 返回 1,否则返回 0*/
local_sub_and_test(v, l)/local64_sub_and_test(v, l) /*给本地原子变量加一:*v 的值加1*/
local_inc(v)/local64_inc(v) /*给本地原子变量减一:*v 的值减1*/
local_dec(v)/local64_dec(v) /*给本地原子变量加一并测试:*v 的值加一,若结果为 0 返回 1,否则返回 0*/
local_inc_and_test(v)/local64_inc_and_test(v) /*给本地原子变量减一并测试:*v 的值减一,若结果为 0 返回 1,否则返回 0*/
local_dec_and_test(v)/local64_dec_and_test(v) /*给本地原子变量做加法并返回:*v 的值增加 i,返回*v 的新值*/
local_add_return(i, v)/local64_add_return(i, v) /*给本地原子变量做减法并返回:*v的值减少 i,返回*v 的新值*/
local_sub_return(i, v)/ local64_sub_return(i, v) /*给本地原子变量加一并返回:*v 的值加一,返回*v 的新值*/
local_inc_return(v)/local64_inc_return(v) /*给本地原子变量减一并返回:*v的值减一,返回*v 的新值*/
local_dec_return(v)/local64_dec_return(v) /*本地原子变量交换:*v 的值更新为 n,返回*v 的原值*/
local_xchg(v, n)/local64_xchg(v, n) /*本地原子变量比较并交换:如果*v 的值等于 0,则*v 的值更新为 n,返回*l 的原值*/
local_cmpxchg(v, 0, n)/local64_cmpxchg(v, 0, n) 

以上相关的内核源码都位于include下面的local相关的.h文件中,这里不做详细的介绍了。

(3)位掩码原子操作

在内核中位掩码原子操作是第三类原子操作,可以给定一个长整数类型的位掩码地址,原子性地设置、清除或改变指定位的值。其主要 API 有:

/*返回位掩码*addr 第 nr 位的值*/
int test_bit(int nr, const volatile unsigned long *addr)/*设置位掩码*addr 第 nr 位的值(设置为 1)*/
void set_bit(unsigned long nr, volatile unsigned long *addr) /*清除位掩码*addr 第 nr 位的值(设置为 0)*/
void clear_bit(unsigned long nr, volatile unsigned long *addr) /*转变位掩码*addr 第 nr 位的值(原值为 0 则设 1,原值为 1 则设 0)*/
void change_bit(unsigned long nr, volatile unsigned long *addr) /*设置位掩码*addr 第 nr 位的值并返回其原值(设置为 1)*/
int test_and_set_bit(unsigned long nr, volatile unsigned long *addr)/*清除位掩码*addr 第 nr 位的值并返回其原值(设置为 0)*/
int test_and_clear_bit(unsigned long nr, volatile unsigned long *addr) /*转变位掩码*addr 第 nr 位的值并返回其原值(原值为 0 则设 1,原值为 1 则设 0)*/
int test_and_change_bit(unsigned long nr, volatile unsigned long *addr)

普通原子操作常用于实现引用计数,而位掩码原子操作的主要用途是用来实现 CPU 位掩码 cpumask 和位图 bitmap 的各种操作。
关于原子操作的更多信息可参阅内核文档 Documentation/atomic_ops.txt 和Documentation/local_ops.txt

读书笔记(2)—— kernel 原子操作相关推荐

  1. VxWorks 6.9 内核编程指导之读书笔记 -- VxWorks kernel application (一)

    #1 什么是内核应用程序? #2 开发内核应用程序注意事项 什么是内核应用程序? 内核应用程序不同于RTP程序,它允许在内核态,与操作系统使用相同的地址空间.因此,它与操作系统会相互干扰.它可以编译成 ...

  2. 《Linux内核设计与实现》读书笔记(十七)- 设备与模块

    本章主要讨论与linux的设备驱动和设备管理的相关的4个内核成分,设备类型,模块,内核对象,sysfs. 主要内容: 设备类型 内核模块 内核对象 sysfs 总结 1. 设备类型 linux中主要由 ...

  3. linux设备驱动读书笔记

    linux设备驱动读书笔记 设备驱动简介 机制:提供什么能力 策略:如何使用这些能力 在编写驱动时, 程序员应当编写内核代码来存取硬件, 但是不能强加特别的策略给用户, 因为不同的用户有不同的需求. ...

  4. linux设备驱动读书笔记(转)

    linux设备驱动读书笔记 设备驱动简介 机制:提供什么能力 策略:如何使用这些能力 在编写驱动时, 程序员应当编写内核代码来存取硬件, 但是不能强加特别的策略给用户, 因为不同的用户有不同的需求. ...

  5. 《Linux内核设计与实现》读书笔记 - 目录 (完结)

    读完这本书回过头才发现, 第一篇笔记居然是 2012年8月发的, 将近一年半的时间才看完这本书(汗!!!). 为了方便以后查看, 做个<Linux内核设计与实现>读书笔记 的目录: < ...

  6. 行人检测 读书笔记 综述

    行人检测 读书笔记 综述(1) 朱文佳-基于机器学习的行人检测关键技术研究 本文是博主对上海交通大学的朱文佳的硕士毕业论文的学习笔记,如果不当或理解错误之处,敬请指导,不胜感激. 绪论 1.1 典型应 ...

  7. 《POSIX多线程程序设计》读书笔记

    <POSIX多线程程序设计>读书笔记 一.      概述 1.    一个UNIX进程可以理解为一个线程加上地址空间.文件描述符和其他数据: 2.    多个线程可以共享一个地址空间,而 ...

  8. 《Deep Learning With Python second edition》英文版读书笔记:第十一章DL for text: NLP、Transformer、Seq2Seq

    文章目录 第十一章:Deep learning for text 11.1 Natural language processing: The bird's eye view 11.2 Preparin ...

  9. 《Effective-Ruby》读书笔记

    本篇是在我接触了 Ruby 很短一段时间后有幸捧起的一本书,下面结合自己的一些思考,来输出一下自己的读书笔记 前言 学习一门新的编程语言通常需要经过两个阶段: 第一个阶段是学习这门编程语言的语法和结构 ...

  10. Linux设备驱动程式之读书笔记(二) [转]

    http://www.sudu.cn/info/html/edu/code/20070102/286543.html setlevel.c 非常实用 google 查找 #define _syscal ...

最新文章

  1. activity中fragment 返回键不退出_分享一波阿里Android客户端面经,我竟连这都答不上来?...
  2. 阿里云上海ACE同城会 | 数据库前沿技术解读及行业应用
  3. 本机电脑与 Android 设备如何进行文件传输?
  4. 黄聪:PowerPoint设计编辑动画的时候图层隐藏和显示问题
  5. Python中class的简单介绍
  6. 转 最小生成树(kruskal 算法 和prim算法)
  7. Python的Web Services客户端
  8. jQuery实现textarea高度根据内容自适应
  9. QML Logical value dose not depend on actual values(M325)
  10. 概率论与数理统计(第四版) 课后习题解析 盛骤、谢式千 编|高等教育出版社 大学课后习题答案
  11. js html导出表格数据格式文件格式,js导出excel表格文件带格式
  12. java开发面试自我介绍模板_java应聘面试自我介绍范文
  13. Win8电脑插入耳机 无声音
  14. 梅森质数(2^n - 1是质数,则n是质数)的证明
  15. iOS 模拟器 获取位置 设置自定义位置
  16. Flutter 开屏方案
  17. 2022年茶叶行业现状分析
  18. 正负数值的正则表达式
  19. 华为mate40计算机,华为Mate40 Pro+电脑,工作事半功倍就差这一步
  20. python图片文本识别的简单实现

热门文章

  1. vmsysjack-clos
  2. 企鹅号发视频技巧视频推荐技巧企鹅号发视频重复,不推荐怎么办呢?
  3. 2022年8月中国数据库排行榜:openGauss重夺榜眼,PolarDB反超人大金仓
  4. 深度:12个行业热点复盘+1个核心盈利指标+6个典型创新案例+4个商业机会展望
  5. 整理mitmproxy安装报错所有问题
  6. linex 简单的命令与文件操作,学习中随时更新
  7. vue中的指令——内置指令
  8. 人大金仓安装教程(国产数据库安装)
  9. 阿里飞冰构建的react项目使用a锚点定位问题
  10. 2023 哔哩哔哩查询用户账号信息api接口源码 无加密