Linux--原子操作

  • 1、原子操作
    • 1.1、概念
    • 1.2、事例
    • 1.3、原子操作结构体介绍
    • 1.4、原子操作的使用
      • 1.4.1、定义
      • 1.4.2、初始化
    • 1.5、原子整形操作 API 函数
      • 1.5.1、事例
    • 1.6、原子位操作 API 函数

1、原子操作

1.1、概念

原子操作提供了指令原子执行,中间没有中断。就像原子被认为是不可分割颗粒一样,原子操作(atomic operation)是不可分割的操作。

1.2、事例

假如现在要对无符号整形变量 a 赋值,值为 3,对于 C 语言来讲很简单,直接就是:

a=3

但是 C 语言要先编译为成汇编指令, ARM 架构不支持直接对寄存器进行读写操作,比如要借助寄存器 R0、 R1 等来完成赋值操作。假设变量 a 的地址为 0X3000000,“a=3”这一行 C语言可能会被编译为如下所示的汇编代码:

ldr r0, =0X30000000         /* 变量 a 地址 */
ldr r1, = 3                /* 要写入的值 */
str r1, [r0]                /* 将 3 写入到 a 变量中 */

从上述代码可以看出, C 语言里面简简单单的一句“a=3”,编译成汇编文件以后变成了 3 句,那么程序在执行的时候肯定是按照示例代码 47.2.1.1 中的汇编语句一条一条的执行。假设现在线程 A要向 a 变量写入 3 这个值,而线程 B 也要向 a 变量写入 30 这个值,我们理想中的执行顺序如下图 所示:

理想情况如上图所示,A线程先给a赋值给30,B线程再给a赋值为30.

但是它一共是六条语句,实际执行时可能是如下情况:


线程 A 最终将变量 a 设置为了 30,而并不是要求的 3!线程B 没有问题。这就是一个最简单的设置变量值的并发与竞争的例子,要解决这个问题就要保证示例代码 中的三行汇编指令作为一个整体运行,也就是作为一个原子存在。 Linux 内核提供了一组原子操作 API 函数来完成此功能, Linux 内核提供了两组原子操作 API 函数,一组是对整形变量进行操作的,一组是对位进行操作的,我们接下来看一下这些 API 函数。

1.3、原子操作结构体介绍

Linux 内核定义了叫做 atomic_t 的结构体来完成整形数据的原子操作,在使用中用原子变量来代替整形变量,此结构体定义在 include/linux/types.h 文件中,定义如下:

/*32位系统下*/
typedef struct {int counter;
} atomic_t;/*64位系统下*/
#ifdef CONFIG_64BIT
typedef struct {long counter;
} atomic64_t;
#endif

1.4、原子操作的使用

1.4.1、定义

atomic_t a; //定义 a

1.4.2、初始化

可以通过宏 ATOMIC_INIT 向原子变量赋初值。

atomic_t a = ATOMIC_INIT(0); //定义原子变量 a 并赋初值为 0

1.5、原子整形操作 API 函数

对原子变量进行操作,比如读、写、增加、减少等等, Linux 内核提供了大量的原子操作 API 函数,如下表 所示:

API 含义
ATOMIC_INIT(int i) 定义原子变量的时候对其初始化。
int atomic_read(atomic_t *v) 读取 v 的值,并且返回。
void atomic_set(atomic_t *v, int i) 向 v 写入 i 值。
void atomic_add(int i, atomic_t *v) 给 v 加上 i 值。
void atomic_sub(int i, atomic_t *v) 从 v 减去 i 值。
void atomic_inc(atomic_t *v) 给 v 加 1,也就是自增。
void atomic_dec(atomic_t *v) 从 v 减 1,也就是自减
int atomic_dec_return(atomic_t *v) 从 v 减 1,并且返回 v 的值。
int atomic_inc_return(atomic_t *v) 给 v 加 1,并且返回 v 的值。
int atomic_sub_and_test(int i, atomic_t *v) 从 v 减 i,如果结果为 0 就返回真,否则返回假
int atomic_dec_and_test(atomic_t *v) 从 v 减 1,如果结果为 0 就返回真,否则返回假
int atomic_inc_and_test(atomic_t *v) 给 v 加 1,如果结果为 0 就返回真,否则返回假
int atomic_add_negative(int i, atomic_t *v) 给 v 加 i,如果结果为负就返回真,否则返回假

相应的也提供了 64 位原子变量的操作 API 函数,这里我们就不详细讲解了,和表 中的 API 函数有用法一样,只是将“atomic_”前缀换为“atomic64_”,将 int 换为 long long。如果使用的是 64 位的 SOC,那么就要使用 64 位的原子操作函数。

1.5.1、事例

atomic_t v = ATOMIC_INIT(0);         /* 定义并初始化原子变零 v=0 */
atomic_set(10);                     /* 设置 v=10 */
atomic_read(&v);                    /* 读取 v 的值,肯定是 10 */
atomic_inc(&v);                     /* v 的值加 1, v=11 */

1.6、原子位操作 API 函数

位操作也是很常用的操作, Linux 内核也提供了一系列的原子位操作 API 函数,只不过原子位操作不像原子整形变量那样有个 atomic_t 的数据结构,原子位操作是直接对内存进行操作,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_bit(int nr, void *p) 将 p 地址的第 nr 位置 1,并且返回 nr 位原来的值。
int test_and_clear_bit(int nr, void *p) 将 p 地址的第 nr 位清零,并且返回 nr 位原来的值。
int test_and_change_bit(int nr, void *p) 将 p 地址的第 nr 位翻转,并且返回 nr 位原来的值。

Linux--原子操作(介绍及其操作函数集)相关推荐

  1. linux 算法函数,数据结构——算法之(012)( linux C 全部字符串操作函数实现)...

    数据结构--算法之(012)( linux C 所有字符串操作函数实现) 题目:实现linux C下常用的字符串操作函数 题目分析: 一.面试中可能经常遇到这样的问题:比如strcpy.memcpy. ...

  2. Linux系统常用目录操作函数

    参考<Linux程序设计>第二版P103 扫描目录: #include <stdio.h> #include <stdlib.h> #include <str ...

  3. linux 文件操作函数,Linux下的文件操作函数及creat用法

    编写Linux应用程序要用到如下工具: (1)编译器:GCC GCC是Linux平台下最重要的开发工具,它是GNU的C和C++编译器,其基本用法为:gcc [options] [filenames]. ...

  4. Linux学习:目录操作函数

    (1)文件重命名 #include <stdio.h> int rename(const char *oldpath, const char *newpath); (2)修改当前进程(应用 ...

  5. 学习C语言对文件的操作函数

       1.2  文件的输入输出函数 键盘.显示器.打印机.磁盘驱动器等逻辑设备, 其输入输出都可以通过文件管理的方法来完成.而在编程时使用最多的要算是磁盘文件, 因此本节主要以磁盘文件为主, 详细介绍 ...

  6. Day53 Linux setitimer函数 信号集操作函数 信号捕捉 SIGCHLD信号

    目录 setitimer函数 信号集操作函数 1.信号集设定 2.igprocmask函数 3.sigpending函数 信号捕捉 1.signal函数 2.sigaction函数 SIGCHLD信号 ...

  7. linux中signal函数返回值,signal函数、sigaction函数及信号集操作函数

    信号是与一定的进程相联系的.也就是说一个进程可以决定在进程中对哪些信号进行什 么样的处理.例如一个进程可以忽略某些信号而只处理其他一些信号另外一个进程还可以选择如何处理信号.总之这些总与特定的进程相联 ...

  8. linux的基础知识——signal信号捕捉,信号集操作函数

    文章目录 1.signal捕捉信号 2.信号集操作函数 3.sigprocmask函数 4.sigpending函数 5.例子1:打印某个进程未决信号集 6.例子2:signal函数的注册捕捉执行函数 ...

  9. Linux系统编程32:进程信号之详解信号集操作函数(sigset_t ,sigpending,sigprocmask)

    文章目录 (1)sigset_t (2)信号集操作函数 (1)sigset_t 前面说过,未决和阻塞分别用位图来表示,于是我们把保存位图这样的数据类型称为sigset_t,sigset_t称为信号集, ...

  10. linux i2c子系统代码分析3 ---操作函数i2c_add_adapter i2c_add_numbered_adapter介绍

    二.i2c子系统操作函数,i2c-core.c 1. kernel/driver/linux/i2c/i2c-core.c /**  * i2c_add_adapter - declare i2c a ...

最新文章

  1. 5-Python3从入门到实战—基础之数据类型(列表-List)
  2. 进击的Android Hook 注入术《一》
  3. SAP SMP的一些截图
  4. TMG学习(十一),保护企业内网上网安全
  5. date日期 和 date时间拼接_函数周期表丨时间丨值丨DATE
  6. 如何清洁和消毒Mac笔记本电脑?
  7. Linux安装SSH
  8. PMI-ACP敏捷项目认证练习题(四)
  9. Hyper-V自定义专用网络网段
  10. 最大公约数与最小公倍数( 初学Java 类与对象 )
  11. apicloud转uniapp_uni-app,wex5,APPcan,ApiCloud几款国内webapp开发框架的选型对比
  12. 根据计算机配置设置bios,设置BIOS让计算机每天都按时自动开机
  13. Self-Intro.
  14. 内江求是中学计算机应用有哪些,内江市求是职业技术学校(内江市求是中学)官网/招生网2020网址...
  15. xenomai网卡驱动分析之一 加载和使用
  16. Noip2017提高组 退役记
  17. 深度优先遍历算法-02最大岛屿问题
  18. 节气生活,邮箱推送,提前预警,告别炎炎夏日下的束手无策
  19. matlab求解全微分函数,利用MATLAB求解微分方程的方法探索
  20. arduino控制轻触开关按键

热门文章

  1. 完整的大数据知识体系,大数据学习路线图
  2. ossim监控mysql_基于OSSIM平台的漏洞扫描详解
  3. 计算机 dc代表什么意思,dc和ac代表什么意思
  4. Mybati从持久层到大气层
  5. missing Change-Id in message footer
  6. 将一个八位的二进制数转换为十进制数
  7. 战略到底在研究什么?
  8. word表格跨页显示时缺少上框线
  9. antd表格分页控件显示英文page
  10. 快速云:如何保护您的域名系统免遭劫持