前言

原子操作可以保证对一个整型数据的修改是排他性的。Linux内核提供了一系列函数来实现内核中的原子操作,这些函数又分为两类,分别针对位和整型变量进行原子操作。位和整型变量的原子操作都依赖于底层CPU的原子操作,因此所有这些函数都与CPU架构密切相关。对于ARM处理器而言,底层使用LDREX和STREX指令,比如atomic_inc()底层的实现会调用到atomic_add()。

头文件Types.h (include\linux)

#include <linux/types.h>

一 整形原子操作相关函数和宏

给原子变量v的值加1

static inline void atomic_inc(atomic_t *v)
{atomic_add_return(1, v);
}

给原子变量的值减1

static inline void atomic_dec(atomic_t *v)
{atomic_sub_return(1, v);
}

给原子变量v加i

static inline void atomic_add(int i, atomic_t *v)
{atomic_add_return(i, v);
}

给原子变量v减i

static inline void atomic_sub(int i, atomic_t *v)
{atomic_sub_return(i, v);
}

三个宏

#define atomic_sub_and_test(i, v)    (atomic_sub_return((i), (v)) == 0)
#define atomic_dec_and_test(v)      (atomic_dec_return(v) == 0)
#define atomic_inc_and_test(v)      (atomic_inc_return(v) == 0)

atomic_inc_and_test东西,就是给原子变量+1,然后,在判断它当前的值是否等于0,其他两个相同。

定义并初始化给原子变量的值:

atomic_t atomic_count;
atomic_set(cm_dev->atomic_count,0);

二 整形原子操作使用方法

atomic_t atomic_count;
atomic_set(&atomic_count,0);
atomic_dec(&atomic_count);//自减1
atomic_inc(&atomic_count);//自增1
atomic_add(5,&atomic_count);//给原子变量加5
atomic_sub(5,&atomic_count);//给原子变量减5if(atomic_dec_and_test(&atomic_count)){printk("原子变量变成0啦\n");
}

三 位原子操作

位原子操作函数主要是用于寄存器的设置。

读取nr位的值

static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
{return ((1UL << (nr % __BITS_PER_LONG)) &(((unsigned long *)addr)[nr / __BITS_PER_LONG])) != 0;
}

设置nr为1

/*** set_bit - Atomically set a bit in memory* @nr: the bit to set* @addr: the address to start counting from** This function is atomic and may not be reordered.  See __set_bit()* if you do not require the atomic guarantees.** Note: there are no guarantees that this function will not be reordered* on non x86 architectures, so if you are writing portable code,* make sure not to rely on its reordering guarantees.** Note that @nr may be almost arbitrarily large; this function is not* restricted to acting on a single-word quantity.*/
static inline void set_bit(int nr, volatile unsigned long *addr)
{unsigned long mask = BIT_MASK(nr);unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);unsigned long flags;_atomic_spin_lock_irqsave(p, flags);*p  |= mask;_atomic_spin_unlock_irqrestore(p, flags);
}

对nr为取反

/*** change_bit - Toggle a bit in memory* @nr: Bit to change* @addr: Address to start counting from** change_bit() is atomic and may not be reordered. It may be* reordered on other architectures than x86.* Note that @nr may be almost arbitrarily large; this function is not* restricted to acting on a single-word quantity.*/
static inline void change_bit(int nr, volatile unsigned long *addr)
{unsigned long mask = BIT_MASK(nr);unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);unsigned long flags;_atomic_spin_lock_irqsave(p, flags);*p ^= mask;_atomic_spin_unlock_irqrestore(p, flags);
}

设置nr为0

/*** clear_bit - Clears a bit in memory* @nr: Bit to clear* @addr: Address to start counting from** clear_bit() is atomic and may not be reordered.  However, it does* not contain a memory barrier, so if it is used for locking purposes,* you should call smp_mb__before_atomic() and/or smp_mb__after_atomic()* in order to ensure changes are visible on other processors.*/
static inline void clear_bit(int nr, volatile unsigned long *addr)
{unsigned long mask = BIT_MASK(nr);unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);unsigned long flags;_atomic_spin_lock_irqsave(p, flags);*p &= ~mask;_atomic_spin_unlock_irqrestore(p, flags);
}

设置n位为1,并返回原来的值

/*** test_and_set_bit - Set a bit and return its old value* @nr: Bit to set* @addr: Address to count from** This operation is atomic and cannot be reordered.* It may be reordered on other architectures than x86.* It also implies a memory barrier.*/
static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
{unsigned long mask = BIT_MASK(nr);unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);unsigned long old;unsigned long flags;_atomic_spin_lock_irqsave(p, flags);old = *p;*p = old | mask;_atomic_spin_unlock_irqrestore(p, flags);return (old & mask) != 0;
}

设置nr位为0,并返回原来的值

/*** test_and_clear_bit - Clear a bit and return its old value* @nr: Bit to clear* @addr: Address to count from** This operation is atomic and cannot be reordered.* It can be reorderdered on other architectures other than x86.* It also implies a memory barrier.*/
static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
{unsigned long mask = BIT_MASK(nr);unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);unsigned long old;unsigned long flags;_atomic_spin_lock_irqsave(p, flags);old = *p;*p = old & ~mask;_atomic_spin_unlock_irqrestore(p, flags);return (old & mask) != 0;
}

对nr位取反,并返回原来的值

/*** test_and_change_bit - Change a bit and return its old value* @nr: Bit to change* @addr: Address to count from** This operation is atomic and cannot be reordered.* It also implies a memory barrier.*/
static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
{unsigned long mask = BIT_MASK(nr);unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);unsigned long old;unsigned long flags;_atomic_spin_lock_irqsave(p, flags);old = *p;*p = old ^ mask;_atomic_spin_unlock_irqrestore(p, flags);return (old & mask) != 0;
}

使用示例

static atomic_t xxx_available = ATOMIC_INIT(1); /* 定义原子变量*/static int xxx_open(struct inode *inode, struct file *filp)
{...if (!atomic_dec_and_test(&xxx_available))  {atomic_inc(&xxx_available);return  - EBUSY;                /* 已经打开*/}...return 0;                           /* 成功 */
}static int xxx_release(struct inode *inode, struct file *filp)
{atomic_inc(&xxx_available);         /* 释放设备 */return 0;
}

结束

linux内核的原子操作简述相关推荐

  1. uboot和linux内核移植流程简述

    一.移植uboot流程 1.从半导体芯片厂下载对应的demo,然后编译测试demo版的uboot 开发板基本都是参考半导体厂商的 dmeo 板,而半导体厂商会在他们自己的开发板上移植好 uboot.l ...

  2. linux内核经常用到的 一个概念“原子操作“

    原子这个概念和我们高中时候学到的物理的概念应该是相同的 但是什么是原子操作: 简单理解就是不可中断的操作 但是可以看一下他的原定义: 经某一操作系统调用所要完成的各个动作作为不可中断的操作,[毕竟(物 ...

  3. Linux内核之内核同步(二)——原子操作

    原子操作 原子操作可以保证指令以原子的方式被执行,执行过程不会被打断.Linux内核提供了一个专门的atomic_t类型(一个原子访问计数器),其定义如下: typedef struct{int co ...

  4. 大话Linux内核中锁机制之原子操作、自旋锁【转】

    转自:http://blog.sina.com.cn/s/blog_6d7fa49b01014q7p.html 多人会问这样的问题,Linux内核中提供了各式各样的同步锁机制到底有何作用?追根到底其实 ...

  5. linux 内核同步--理解原子操作、自旋锁、信号量(可睡眠)、读写锁、RCU锁、PER_CPU变量、内存屏障

    内核同步 内核中可能造成并发的原因: 中断–中断几乎可以在任何时刻异步发生,也就可以随时打断当前正在执行的代码. 软中断和tasklet–内核能在任何时刻唤醒或调度软中断和tasklet,打断当前正在 ...

  6. 【Linux】linux内核原子操作的实现

    所谓原子操作,就是"不可中断的一个或一系列操作". 硬件级的原子操作:在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是"原子操作&qu ...

  7. linux内核原子操作的实现

    所谓原子操作,就是"不可中断的一个或一系列操作". 硬件级的原子操作:在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是"原子操作&qu ...

  8. 原子操作 - linux内核锁(一)

    "原子"是不可分割的意思,原子操作是指一个实际运行的操作不可分割,这个运行必然会被执行并完成而不会被另外一个任务或者事件打断.也就说,它是最小的执行单位,不可能有比它更小的执行单位 ...

  9. linux内核原子操作使用简介

    驱动开发住常见的一个问题:就是一个驱动可以被多个进程同时打开,使用,这样会导致驱动功能混乱. ./app & ./app & ./app   可以同时打开这个设备,可通过文件描述符调用 ...

最新文章

  1. 预训练是 AI 未来所需要的全部吗?
  2. SpringBoot中使用@Mapper注解需要哪个包
  3. c++ 类的继承与派生
  4. Codeforces626B - Cards【模拟】
  5. python教授_Python为何如此优秀?斯坦福教授告诉你!
  6. python魔法方法与函数_在Python中画图(基于Jupyter notebook的魔法函数)
  7. java之歌_程序员之歌
  8. 谁说Dota2赢了人类的AI太水?连比尔·盖茨都啧啧称赞了
  9. -bash: pip: command not found错误
  10. java使用org.w3c.dom解析XML文档,创建、增删查改,保存,读取,遍历元素等操作
  11. 计算机精品视频教程合集
  12. 推荐一款能够将爱奇艺qsv、腾讯qlv、优酷kux完美转换成mp4的三合一全能格式转换器
  13. VelocityTracker使用总结
  14. 【规范】万字集大成的SCHPCB设计规范和AD的使用
  15. 搭建ftp服务器根目录文件夹,ftp服务器根目录传文件夹
  16. 压六类双绞线网线水晶头,
  17. 微信 及支付宝 支付接口 功能
  18. SpringBoot企业微信点餐系统
  19. MobaXterm登录密码重置
  20. 软件测试需要掌握的技能

热门文章

  1. dowhile实现求水仙花数
  2. 拓嘉辰丰电商:如何投诉拼多多商家一直不发货
  3. 树莓派-微信-网易云音乐播放器
  4. 搭建node版本下载服务器(node版本高速镜像)
  5. mr编程实现手机流量统计和读取MySQL数据
  6. vulnhub THE PLANETS: EARTH
  7. 教育之星 计算机,冉冉升起的教育之星
  8. 『Citric』天空中的繁星 · DP
  9. Edge浏览器出现翻译不了页面,扩展插件无法下载解决办法
  10. 使用 Microsoft AI 打造你的首款智能机器人(入门只需要1小时)