`
huangyongxing310
  • 浏览: 483465 次
  • 性别: 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 下,内核中常用的同步机制包括:原子操作、自旋锁和信号量。 1. 原子操作 原子操作就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就说,它的最小的执行单位,不可能有比它更小的执行单位。...

    操作系统同步研究——Linux内核同步机制.pdf

    2. Linux 内核同步机制:Linux 内核中有多种同步机制,包括信号量、自旋锁、原子操作和等待队列等。这些机制可以用于实现系统的同步,确保系统的正确性和可靠性。 3. 等待队列和异步信号:等待队列是一个基本的功能...

    Linux操作系统内核同步机制分析.pdf

    在Linux操作系统中,内核同步机制是确保多任务环境下内核数据结构一致性的重要手段。本文将深入探讨Linux内核2.4版本中的同步机制,包括其基本原理和实现的各种锁机制。 Linux操作系统支持并发执行多个任务,这在...

    Linux同步互斥机制

    Linux 内核使用 atomic_t 数据结构来实现原子操作,atomic_add() 和 atomic_sub() 函数用于实现原子加法和原子减法操作。 在 semaphore 机制中,down() 函数的执行过程可以分为几步: 1. 将 semaphore 的 count ...

    北大OS-Nachos同步机制

    通过该同步机制的实现,可以学习到Nachos操作系统的同步机制的实现细节,同时也可以学到Linux操作系统中信号量的实现细节。该同步机制的实现也可以应用于其他操作系统中,例如在Android操作系统中,可以使用该同步...

    linux_锁_原子_自旋

    在Linux操作系统中,锁、原子操作和自旋锁是内核并发控制的重要机制,用于确保多线程环境下的数据一致性与正确性。这些概念在构建高效、可靠的并发程序时至关重要。 **1. Linux锁** Linux内核中的锁主要用于保护...

    linux内核同步机制1

    在Linux系统中,有多种同步机制,如原子操作、自旋锁和信号量,它们各有特点,用于不同的场景。这里我们将重点讨论自旋锁和信号量。 自旋锁是专为多处理器环境设计的一种轻量级锁定机制,它不允许持锁任务睡眠。...

    Linux内核的同步机制

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

    【正点原子】I.MX6U嵌入式Linux C应用编程指南V1.4

    《【正点原子】I.MX6U 嵌入式 Linux C 应用编程指南 V1.4》 本资源为嵌入式 Linux C 应用编程指南,基于 I.MX6U 微处理器,旨在帮助开发者快速上手嵌入式 Linux 应用开发。该指南涵盖了嵌入式 Linux 的基本概念、...

    linux上实现多进程和多线程实现同步互斥(源代码)

    总结,Linux上的多进程和多线程编程涉及复杂的同步互斥操作,开发者需要理解各种同步机制,根据具体需求选择合适的方法。通过阅读和学习提供的源代码,可以加深对这些概念的理解,提升实际开发能力。

    Linux内核分析与应用课件第7章(一)内核同步概述.pdf

    本文主要介绍Linux内核同步机制的概述,讨论了内核同步的必要性、竞争条件、临界区的概念、保护临界区的措施、原子操作等重要概念。 内核同步机制的必要性 在Linux内核中,存在多个任务并发执行,包括进程、中断、...

    Linux设备驱动中的互斥机制.pdf

    Linux 提供了多种互斥机制,包括中断屏蔽、原子操作、信号量和自旋锁等。本文将详细介绍这些互斥机制的优缺点和使用方法。 1. 中断屏蔽 中断屏蔽是避免竞态的简单方法,即在进入临界区之前屏蔽系统的中断。这可以...

    zynq的linux驱动5-使用原子操作实现mio资源的竞争保护

    - `atomic_xchg()`: 用于交换操作,它会原子地将变量的值与提供的新值交换,并返回旧值。 2. **实现MIO资源竞争保护**: - 创建一个`atomic_t`变量,表示MIO资源的状态(例如,未使用或正在使用)。 - 在进程...

    linux线程间同步详细说明

    Linux提供了__sync_synchronize、__sync_fetch_and_add等原子操作函数,可以用于实现简单的同步需求,无需使用上述复杂的同步机制。 七、线程局部存储(Thread-Local Storage) 线程局部存储允许每个线程拥有自己的...

    Linux应用程序之线程通信

    总结起来,Linux中的线程通信涉及了多种同步机制,如互斥锁、原子操作和自旋锁。理解和掌握这些技术对于编写高效、安全的多线程程序至关重要。通过分析压缩包中的源代码,你可以更深入地了解这些概念,并学习如何在...

    linux OS.zip_linux os_linux进程同步_多进程os

    同步机制包括信号量、管程、条件变量等,确保关键操作的原子性和避免死锁的发生。 在描述中提到的临界区(Critical Section)问题,是进程同步的核心。临界区是指每个进程中访问临界资源的代码段。为了保证资源的...

    linux驱动工程面试必问知识点

    Linux 中的同步机制是指操作系统对多线程或多进程之间的同步问题的解决方案。常见的同步机制包括spinlock、信号量、mutex 等。 6. Linux RCU 原理 RCU(Read-Copy-Update)是指 Linux 操作系统中的一种同步机制...

    Linux内核同步机制的自旋锁原理及综合应用实例

    Linux内核同步机制中的自旋锁(Spinlock)是一种用于多处理器系统中保证并发安全的重要工具。自旋锁的设计理念是,在持有锁的进程或线程释放锁之前,其他尝试获取该锁的线程会“自旋”等待,而不是进入睡眠状态。这...

    深入linux设备驱动程序内核机制 pdf

    10. **内核同步与并发控制**:在多任务环境中,内核需要确保对共享资源的访问是线程安全的,因此,锁、信号量、原子操作等同步原语在设备驱动编程中扮演重要角色。 11. **调试技术**:了解如何使用`dmesg`、`strace...

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

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

Global site tag (gtag.js) - Google Analytics