`
huangyongxing310
  • 浏览: 477808 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

Linux的原子操作与同步机制

阅读更多
Linux的原子操作与同步机制


并发问题
例如C语言语句“count++;”在未经编译器优化时生成的汇编代码为多条机器指令来实现的。


例子:
假设count变量初始值为0。进程1执行完“mov eax, [count]”后,寄存器eax内保存了count的值0。此时,
进程2被调度执行,抢占了进程1的CPU的控制权。进程2执行“count++;”的汇编代码,将累加后的count值
1写回到内存。然后,进程1再次被调度执行,CPU控制权回到进程1。进程1接着执行,计算count的累加
值仍为1,写回到内存。虽然进程1和进程2执行了两次“count++;”操作,但是count实际的内存值为1,而
不是2!



单处理器原子操作
解决这个问题的方法是,将“count++;”语句翻译为单指令操作。
Intel x86指令集支持内存操作数的inc操作,这样“count++;”操作可以在一条指令内完成。因为进程的上下文
切换是在总是在一条指令执行完成后,所以不会出现上述的并发问题。对于单处理器来说,一条处理器指令就
是一个原子操作。



多处理器原子操作
但是在多处理器的环境下,例如SMP架构,这个结论不再成立。我们知道“inc [count]”指令的执行过程分为三步:
1)从内存将count的数据读取到cpu。
2)累加读取的值。
3)将修改的值写回count内存。
这又回到前面并发问题类似的情况,只不过此时并发的主题不再是进程,而是处理器。

Intel x86指令集提供了指令前缀lock用于锁定前端串行总线(FSB),保证了指令执行时不会受到其他处理器的干扰。
使用lock指令前缀后,处理器间对count内存的并发访问(读/写)被禁止,从而保证了指令的原子性。



arm原子操作实现
在arm的指令集中,不存在指令前缀lock,那如何完成原子操作呢?
在ARMv6之前,swp指令就是通过锁定总线的方式完成原子的数据交换,但是影响系统性能。ARMv6之后,一般使用ldrex
和strex指令对代替swp指令的功能。



自旋锁中的原子操作
	1:
	lock   decb [lock->slock]
	jns    3
	2:
	rep    nop
	cmpb   $0, [lock->slock]
	jle    2
	jmp    1
	3:


其中lock->slock字段初始值为1,执行原子操作decb后值为0。符号位为0,执行jns指令跳转到3,完成自旋锁的加锁。

当再次申请自旋锁时,执行原子操作decb后lock->slock值为-1。符号位为1,不执行jns指令。进入标签2,执行一组
nop指令后比较lock->slock是否小于等于0,如果小于等于0回到标签2进行循环(自旋)。否则跳转到标签1重新申请
自旋锁,直到申请成功。

自旋锁释放时会将lock->slock设置为1,这样保证了其他进程可以获得自旋锁。



信号量中的原子操作
信号量的申请操作由函数down实现
	lock   decl [sem->count]
	js 2
	1:
	<========== another section ==========>
	2:
	lea    [sem->count], eax
	call   __down_failed
	jmp 1


信号量的sem->count一般初始化为一个正整数,申请信号量时执行原子操作decl,将sem->count减1。如果该值减为负数
(符号位为1)则跳转到另一个段内的标签2,否则申请信号量成功。

标签2被编译到另一个段内,进入标签2后,执行lea指令取出sem->count的地址,放到eax寄存器作为参数,然后调用函数
__down_failed表示信号量申请失败,进程加入等待队列。最后跳回标签1结束信号量申请。


信号量的释放操作由函数up实现。
	lock   incl sem->count
	jle     2
	1:
	<========== another section ==========>
	2:
	lea    [sem->count], eax
	call   __up_wakeup
	jmp    1


释放信号量时执行原子操作incl将sem->count加1,如果该值小于等于0,则说明等待队列有阻塞的进程需要唤醒,跳转到标签2,
否则信号量释放成功。

标签2被编译到另一个段内,进入标签2后,执行lea指令取出sem->count的地址,放到eax寄存器作为参数,然后调用函数__up_wakeup
唤醒等待队列的进程。最后跳回标签1结束信号量释放。

例子:

代码1(低优先级)(线程1)
代码1down
代码1down处理代码
代码1up


代码2(高优先级)(线程2)
代码2down
代码2down处理代码
代码2up

分析:
代码1down成功就运行代码1down处理代码,(假如代码2刚运行到代码2down,因没有得到信号量,所以被挂起了),代码1处理完
代码1down处理代码,到代码1up时会看有没有其它线程等待信号量(线程2等待着),所以系统恢复线程2进行运行,运行
代码2down处理代码,再运行到代码2up,发现没有就退出直到线程2不再运行,系统恢复线程1进行运行,运行到代码1up时被
系统挂起时下一条代码,再运行代码1其他代码直到再次被挂起。


原文参考:http://www.cnblogs.com/fanzhidongyzby/p/3654855.html
分享到:
评论

相关推荐

    Linux内核同步机制

    内核很容易产生竞争条件。同一时间可能有多个内核执行流在执行,内核的许多特性都要求能够并发地访问共享数据,这就要求有同步机制来同步各执行单元对共享数据的访问以保证不出现竞争条件

    Linux内核的同步机制

     在主流的Linux内核中包含了几乎所有现代的操作系统具有的同步机制,这些同步机制包括:原子操作、信号量(semaphore)、读写信号量(rw_semaphore)、spinlock、BKL(Big Kernel Lock)、rwlock、brlock(只包含在...

    linux之线程同步的概要介绍与分析

    为了实现这一目标,Linux提供了一系列强大的线程同步机制和工具,让开发者能够高效、安全地控制线程间的执行顺序。以下是一些关键的线程同步方法及其简要描述: 1. **互斥锁(Mutex)**:互斥锁是最基本也是最常用...

    清华大学Linux操作系统原理与应用

    7.2.1 原子操作 153 7.2.2 自旋锁 155 7.2.3 信号量 156 7.3 并发控制实例 157 7.3.1 内核任务及其并发关系 158 7.3.2 实现机制 158 7.3.3 关键代码解释 162 7.3.4 实现步骤 163 习题7 164 第8章 文件系统 165 8.1 ...

    Linux RCU机制详解

    也就是说是一个原子操作.因它更改指针指向没必要考虑它的同步.只需要考虑cache的影响. 3:读者是可以嵌套的.也就是说rcu_read_lock()可以嵌套调用. 4:读者在持有rcu_read_lock()的时候,不能发生进程上下文切换.否则,...

    linux操作系统内核技术-uestc课件

     7掌握内核同步原理和方法:原子操作,自旋锁,(读—写)信号量,完成变量,bkl,seqlock和延迟内核抢占。了解指令“路障”。(4小时)  8介绍系统时钟和硬件定时器,单处理器和多处理器上的linux计时体系结构,...

    Linux2.6内核标准教程(共计8-- 第1个)

    最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU这两种新的 同步机制。 《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关...

    Linux2.6内核标准教程(共计8--第6个)

    最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU这两种新的 同步机制。 《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关...

    Linux2.6内核标准教程(共计8--第8个)

    最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU这两种新的 同步机制。 《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关...

    Linux2.6内核标准教程(共计8--第3个)

    最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU这两种新的 同步机制。 《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关...

    Linux2.6内核标准教程(共计8--第7个)

    最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU这两种新的 同步机制。 《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关...

    深入分析Linux内核源码

    4.8.2原子操作 4.8.3 自旋锁、读写自旋锁和大读者自旋锁 4.9 本章小节 第五章进程调度 5.1 Linux时间系统 5.1.1 时钟硬件 5.1.2 时钟运作机制 5.1.3 Linux时间基准 5.1.4 Linux的时间系统 5.2 时钟...

    Linux2.6内核标准教程(共计8--第4个)

    最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU这两种新的 同步机制。 《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关...

    Linux2.6内核标准教程(共计8--第2个)

    最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU这两种新的 同步机制。 《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关...

    Linux2.6内核标准教程(共计8--第5个)

    最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU这两种新的 同步机制。 《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关...

    Linux下的“锁”事儿

     我们晓得在Linux内核中,同步机制是一大特性。比较经典的有原子操作、spin_lock(自旋锁)、mutex(互斥锁)、semaphore(信号量)等。  原子操作  原子操作,也是数据库事务的一大特性。是该操作绝不会在...

    linux线程间的同步与互斥知识点总结

    是一种同步机制,一个线程用于修改这个变量使其满足其它线程继续往下执行的条件,其它线程则接收条件已经发生改变的信号。 条件变量操作? 初始化和销毁 pthread_cond_wait 条件不满足 会释放锁并阻塞等待 , 这个函数是...

    Android驱动开发权威指南

    9.2 Linux中常用的同步访问技术 9.2.1中断屏蔽 9.2.2原子操作 9.2.3自旋锁 9.2.4信号量 9.2.5互斥灯 9.3增加并发控制的virtualchar驱动 第10章Linux设备的阻塞式与非阻塞式访问 10.1阻塞式与非阻塞式访问 10.1.1等待...

    疯狂内核之——进程管理子系统

    4.3 原子操作 199 4.4 优化屏障和内存壁垒 203 4.4.1 优化屏障 204 4.4.2 内存壁垒 204 4.5 自旋锁 206 4.6 读写自旋锁 211 4.6.1 为读获取和释放一个锁 213 4.6.2 为写获取或释放一个锁 214 4.7 顺序锁 215 4.8 RCU...

Global site tag (gtag.js) - Google Analytics