linux原子/位操作

转载 2015年11月19日 18:49:15

1、基本概念

原子操作可以保证指令以原子的方式执行,执行过程不被打断。它通过把读取和修改变量的行为包含在一个单步中执行,从而防止了竞争的发生,保证操作结果总是一致的。

例如:

int i=9;

线程1:

i++

i=9 OR i=8

线程2

i–;

i=9 OR i=8

两个线程并发的执行,导致结果不确定性。原子操作的作用和信号量机制是一样,都是为了防止同时访问临界资源,保证结果的一致性。大多数硬件体系结构要么本来就支持简单的原子操作,要么就为音频执行提供了锁内在总线的指令,例如x86平台上,就支持CPU锁总线操作,汇编指令前缀“LOCK”就可以将总线锁作,直到指令结束时锁打开;而有些硬件体系结构本身就不太支持原子操作,比如SPARC,但是Linux内核通过一些方法,做到了原子操作。

原子操作在Linux内核里分为原子整数操作和原子位操作,下面我们来看看这两个操作用法。

2、原子整数操作

针对整数的原子操作只能对atomic_t类型的数据进行处理,之所以没有用C语言的int类型,主要有两个原因:

1、让原子函数只接受atomic_t类型的操作数,可以确保原子操作只与这种特殊类型数据一起使用,防止该类型数据不会传给其它非原子操作

2、使用atomic_t类型确保编译器不对相应的值进行访问优化

3、在不同体系结构上实现原子操作的时候,使用atomic_t可以屏蔽其间的差异。

尽管Linux的整型数据都是32位的,但是使用atomic_t的代码只能将将该类型的数据当作24位来用,我们看看atomic_t的数据

|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|

|      带符号24位整形数据        |   锁   |

|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|

|10987654321098765432109876543210|

| 3         2         1          |

|            32位atmoic_t         |

|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|

我们看到atomic_t中嵌入了一个8bit的锁,因为SPARC体系结构对原子操作缺乏指令级的支持,所以只能使用利用该锁来避免对原子类型数据的并发访问,对于原子操作的使用,看下面例子:

1 int a=3;
2 atomic_t v=ATOMIC_INIT(a);
3 atomic_add(&v,a);
4 atomic_inc(&v);

在上面例子中,我们先定义并初始化了一个atomic_t变量,再对其进行了加法、自加操作。在Linux内核中提供了一系统的原子整数操作函数。

原子整数操作 描述
ATOMIC_INIT(int i) 在声明一个atmoic_t变量时,将它初始化为i
ATOMIC_INIT(int i) 在声明一个atmoic_t变量时,将它初始化为i
int atmoic_read(atmoic_t *v) 原子地读取整数变量v
void atmoic_set(atmoic_t *v,int i) 原子地设置v值为i
void atmoic_add(atmoic_t *v,int i) 原子地从v值加i
void atmoic_sub(atmoic_t *v,int i) 原子地从v值减i
void atmoic_inc(atmoic_t *v) 原子地从v值加1
void atmoic_dec(atmoic_t *v) 原子地从v值减1
int atmoic_sub_and_test(int i,atmoic_t *v) 原子地从v值减i,如果结果等于0返回真,否则返回假
int atmoic_add_negative(int i,atmoic_t *v) 原子地从v值减i,如果结果是负数返回真,否则返回假
int atmoic_dec_and_test(atmoic_t *v) 原子地给v减1,如果结果等于0返回真,否则返回假
int atmoic_inc_and_test(atmoic_t *v) 原子地给v加1,如果结果等于0返回真,否则返回假

原子操作最常见的用途就是实现计数器,使用复杂的锁机制来保护一个单纯的计数是很笨拙的,原子操作比起复杂的同步方法来说,给系统带来的开销小,对高速缓存行的影响也小。

3、原子位操作

除了原子整数操作外,内核还提供了一组针对位这一级数据进行操作的函数,位操作函数是对普通的内在地址进行操作的,它的参数是一个指针和一个位号。由于是对普通的指针进程操作,所以没有像atomic_t这样的类型约束。

1 unsigned long word = 0;
2 set_bit(0,&word);
3 clear_bit(0,&word);
4 change_bit(0,&word);//翻转第0位的值
原子整数操作 描述
void set_bit(int nr,void *addr) 原子地设置addr所指对象的第nr位
void clear_bit(int nr,void *addr) 原子地清空addr所指对象的第nr位
void change_bit(int nr,void *addr) 原子地翻转addr所指对象的第nr位
int test_and_set_bit(int nr,void *addr) 原子地设置addr所指对象的第nr位,并返回原先的值
int test_and_clear_bit(int nr,void *addr) 原子地清空addr所指对象的第nr位,并返回原先的值
int test_and_change_bit(int nr,void *addr) 原子地翻转addr所指对象的第nr位,并返回原先的值
int test_bit(int nr,void *addr) 原子地返回addr所指对象的第nr位

相关文章推荐

linux内核原子变量与原子位操作API

原子变量: arch/arm/include/asm/atomic.h 定义并初始化 atomic_t v = ATOMIC_INIT(0); 写 void atomic_set(atomic_t...

原子位操作

原子位操作与非原子位操作的区别

原子操作的实现原理

1. 引言 原子(atom)本意是“不能被进一步分割的最小粒子”,而原子操作(atomic operation)意为"不可被中断的一个或一系列操作" 。在多处理器上实现原子操作就变得有点复杂。本文让我...

嵌入式Linux下C程序设计--位操作

  • 2012年09月03日 11:22
  • 867KB
  • 下载

28 atomic_t原子数与原子位操作

假如驱动里实现对write操作进行计算次数,当进程读操作时输出次数. test.c:#include #include #include #include int count = 0; ssi...
  • jklinux
  • jklinux
  • 2017年06月12日 10:36
  • 439

linux位操作

Linux内核提供了一些对位操作的方法: include/asm-generic/bitops/atomic.h [cpp] view plaincopyprint? ...

linux内核部件之---原子性操作atomic_t

在任何处理器平台下,都会有一些原子性操作,供操作系统使用,我们这里只讲x86下面的。在单处理器情况下,每条指令的执行都是原子性的,但在多处理器情况下,只有那些单独的读操作或写操作才是原子性的。为了弥补...

07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-按键驱动程序之异步通知机制+原子操作+互斥信号量+阻塞与非阻塞+定时器去抖

一、异步通知机制 从按键的实现方式来说,可以分为以下几种方式 查询方式,极度耗费CPU资源中断方式,平时休眠,按键按下,唤醒休眠poll机制,不需要一直read,根据poll返回值来决定是否rea...

Linux 互斥锁、原子操作实现原理

futex(快速用户区互斥的简称)是一个在Linux上实现锁定和构建高级抽象锁如信号量和POSIX互斥的基本工具。它们第一次出现在内核开发的2 5 7版;其语义在2 5 40固定下来,然后在2 6 x...

Linux原子操作--Atomic Operations

转载自:高手进阶必读:Linux内核的同步机制-->原子操作 http://soft.yesky.com/os/lin/10/2303010.shtml        所谓原子操作,就是该操作绝不会...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux原子/位操作
举报原因:
原因补充:

(最多只允许输入30个字)