`
cuker919
  • 浏览: 88625 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

关于单CPU,多CPU上的原子操作

 
阅读更多

所谓原子操作,就是"不可中断的一个或一系列操作" 。

硬件级的原子操作:
在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是" 原子操作",因为中断只能发生于指令之间。这也是某些CPU指令系统中引入了test_and_set、test_and_clear等指令用于临界资源互斥的原因。

在对称多处理器(Symmetric Multi-Processor)结构中就不同了,由于系统中有多个处理器在独立地运行,即使能在单条指令中完成的操作也有可能受到干扰。

在x86 平台上,CPU提供了在指令执行期间对总线加锁的手段。CPU芯片上有一条引线#HLOCK pin,如果汇编语言的程序中在一条指令前面加上前缀"LOCK",经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCK pin的电位拉低,持续到这条指令结束时放开,从而把总线锁住,这样同一总线上别的CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中的

原子性。
软件级的原子操作:
软件级的原子操作实现依赖于硬件原子操作的支持。
对于linux而言,内核提供了两组原子操作接口:一组是针对整数进行操作;另一组是针对单独的位进行操作。
2.1. 原子整数操作
针对整数的原子操作只能对atomic_t类型的数据处理。这里没有使用C语言的int类型,主要是因为:

1) 让原子函数只接受atomic_t类型操作数,可以确保原子操作只与这种特殊类型数据一起使用

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

3) 使用atomic_t类型可以屏蔽不同体系结构上的数据类型的差异。尽管Linux支持的所有机器上的整型数据都是32位,但是使用atomic_t的代码只能将该类型的数据当作24位来使用。这个限制完全是因为在SPARC体系结构上,原子操作的实现不同于其它体系结构:32位int类型的低8位嵌入了一个锁,因为SPARC体系结构对原子操作缺乏指令级的支持,所以只能利用该锁来避免对原子类型数据的并发访问。

原子整数操作最常见的用途就是实现计数器。原子整数操作列表在中定义。原子操作通常是内敛函数,往往通过内嵌汇编指令来实现。如果某个函数本来就是原子的,那么它往往会被定义成一个宏。

在编写内核时,操作也简单:

atomic_t use_cnt;

atomic_set(&use_cnt, 2);

atomic_add(4, &use_cnt);

atomic_inc(use_cnt);

2.2. 原子性与顺序性

原子性确保指令执行期间不被打断,要么全部执行,要么根本不执行。而顺序性确保即使两条或多条指令出现在独立的执行线程中,甚至独立的处理器上,它们本该执行的顺序依然要保持。

2.3. 原子位操作

原子位操作定义在文件中。令人感到奇怪的是位操作函数是对普通的内存地址进行操作的。原子位操作在多数情况下是对一个字长的内存访问,因而位号该位于0-31之间(在64位机器上是0-63之间),但是对位号的范围没有限制。

编写内核代码,只要把指向了你希望的数据的指针给操作函数,就可以进行位操作了:

unsigned long word = 0;

set_bit(0, &word); /*第0位被设置*/

set_bit(1, &word); /*第1位被设置*/

clear_bit(1, &word); /*第1位被清空*/

change_bit(0, &word); /*翻转第0位*/

为什么关注原子操作?
1)在确认一个操作是原子的情况下,多线程环境里面,我们可以避免仅仅为保护这个操作在外围加上性能开销昂贵的锁。
2)借助于原子操作,我们可以实现互斥锁。
3)借助于互斥锁,我们可以把一些列操作变为原子操作。

GNU C中x++是原子操作吗?
答案不是。x++由3条指令完成。x++在单CPU下不是原子操作。
对应3条汇编指令
movl x, %eax
addl $1, %eax
movl %eax, x
在vc2005下对应
++x;
004232FA mov eax,dword ptr [x]
004232FD add eax,1
00423300 mov dword ptr [x],eax
仍然是3条指令。
所以++x,x++等都不是原子操作。因其步骤包括了从内存中取x值放入寄存器,加寄存器,把值写入内存三个指令。

如何实现x++的原子性?
在单处理器上,如果执行x++时,禁止多线程调度,就可以实现原子。因为单处理的多线程并发是伪并发。
在多处理器上,需要借助cpu提供的Lock功能。锁总线。读取内存值,修改,写回内存三步期间禁止别的CPU访问总线。同时我估计使用Lock指令锁总线的时候,OS也不会把当前线程调度走了。要是调走了,那就麻烦了。

在多处理器系统中存在潜在问题的原因是:
不使用LOCK指令前缀锁定总线的话,在一次内存访问周期中有可能其他处理器会产生异常或中断,而在异常处理中有可能会修改尚未写入的地址,这样当INC操作完成后会产生无效数据(覆盖了前面的修改)。

spinlock 用于CPU同步, 它的实现是基于CPU锁定数据总线的指令.
当某个CPU锁住数据总线后, 它读一个内存单元(spinlock_t)来判断这个spinlock 是否已经被别的CPU锁住. 如果否, 它写进一个特定值, 表示锁定成功, 然后返回. 如果是, 它会重复以上操作直到成功, 或者spin次数超过一个设定值. 锁定数据总线的指令只能保证一个机器指令内, CPU独占数据总线.
单CPU当然能用spinlock, 但实现上无需锁定数据总线.

spinlock在锁定的时候,如果不成功,不会睡眠,会持续的尝试,单cpu的时候spinlock会让其它process动不了.

分享到:
评论

相关推荐

    机组大作业:基于RISC-V架构的45条指令单周期CPU设计

    内含CPU所有Verilog源码、论文详细解析,作业成绩为优秀 所有代码和论文皆为原创,严禁二次转载!

    CPU运算突破瓶颈的希望——原子级晶体管.pdf

    CPU运算突破瓶颈的希望——原子级晶体管.pdf

    多线程CPU压力测试源码

    源码调用了精易模块,。注意!老电脑一定要不要勾选不延迟!...本程序用于测试计算CPU在多线程下同时计算对CPU产生的压力!。没有做防护!如果需要做防炸机在第二个时钟下写代码!。本程序原理十分简单!。@氢原子。

    CPU处理器是怎么做出来的

    CPU处理器是怎么制造出来的。...这些硅经过多个步骤纯化后,达到足以制成芯片的质量 — 每十亿个硅原子中,仅能出现一个别种的原子。最后这些高纯度的硅原子结晶成一颗巨大的单晶硅(直径 8~12 吋),重可达 100 kg!

    【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.2.pdf

    PC 上完成的,只要安装好 Ubuntu 操作系统即可。 第二篇: ARM 裸机开发 从本篇开始我们就正式开始使用开发板学习了,本篇通过数十个裸机例程来帮助大家了解 I.MX6UL 这颗 CPU。为以后的 Linux 驱动开发做准备,...

    笔记-3、原子操作CAS1

    循环(死循环,自旋)里不断的进行CAS操作CAS的问题A---》B----》A,版本号: A1B2-A3CAS操作长期不成功,cpu不断的循环,Jdk中相关原子

    电感耦合等离子体-原子发射光谱法测定CPU导热硅脂中的铅和镉.pdf

    电感耦合等离子体-原子发射光谱法测定CPU导热硅脂中的铅和镉.pdf

    正点原子:STM32F103(战舰)、STM32F407(探索者)、STM32F103(MINI)原理图和PCB

    ALIENTEK战舰STM32F103,资源十分丰富,并把STM32F103的内部资源发挥到了极致,基本所有STM32F103的内部资源,都可以在此开发板上验证,同时扩充丰富的接口和功能模块,整个开发板显得十分大气。 板载资源如下所示...

    C#中使用Interlocked进行原子操作的技巧

    使用.NET提供的Interlocked类可以对一些数据进行原子操作,看起来似乎跟lock锁一样,但它并不是lock锁,它的原子操作是基于CPU本身的,非阻塞的,所以要比lock的效率高

    java并发理论基础、可见性、原子性、有序性详解

    本资源涵盖了Java并发编程的理论基础和实践,主要包括...而在计算密集型操作中,多核CPU可以同时运行多个任务,从而更快地完成任务。我们还将讲解Java多线程开发的好处和坏处,并探讨如何尽量减少由多线程带来的问题。

    Java并发面试题整理(答案)

    从程序运行效率的角度来看,单核 CPU 不但不会发挥出多线程的优势,反而会因为在单核 CPU 上运行多线程导致线程上下文的切换,而降低程序整体的效率。但是单核 CPU 我们还是要应用多线程,就是为了防止阻塞。试想,...

    java多线程安全性基础介绍.pptx

    多个线程操作共享对象导致的状态不一致问题 原因 共享资源的竞态条件问题 问题 竞态条件 指令重排序 工作内存中主内存同步延迟 解决 要有安全策略文档或注释 不共享 线程封闭 仅在单线程内访问数据 栈...

    Lightweight 轻量级通用环缓冲区管理器库

    对于架构小于 (AVR) 的 CPU 系统,缓冲区写入的读写操作需要原子保护sizeof(size_t) 适用于在内存之间传输 DMA 和向内存传输,缓冲区和应用程序内存之间的开销为零 支持数据速览、跳过读取和前进写入 实现对事件...

    15、CPU缓存架构详解&高性能内存队列Disruptor实战(1).pdf

    11-线程池 ThreadPoolExecutor 底层原理源码分析(上)-周瑜.pdf 12-线程池 ThreadPoolExecutor底层原理源码分析(下)-周瑜.pdf 13、线程池 ForkJoinPool实战及其工作原理分析 (1).pdf 14、深入理解井发可见性、...

    14、深入理解并发可见性、有序性、原子性与JMM内存模型(1).pdf

    11-线程池 ThreadPoolExecutor 底层原理源码分析(上)-周瑜.pdf 12-线程池 ThreadPoolExecutor底层原理源码分析(下)-周瑜.pdf 13、线程池 ForkJoinPool实战及其工作原理分析 (1).pdf 14、深入理解井发可见性、...

    matlab激光仿真源码-AtomECS:冷原子模拟代码

    散射光的原子上的多普勒力,包括引起多普勒温度极限的随机波动。 磁场,在网格上或通过简单的分析模型实现。 由烤箱产生的原子。 在模拟体积(例如,腔室)的表面上生成的原子。 冷却光束,由其失谐和高斯强度分布...

    Java并发编程实战之互斥锁.pptx

    原子性问题的源头是线程切换,多个线程同时操作同一个变量。这样就会出现线程冲突的问题。所以需要一种机制保持在多核CPU下,同一个时刻只有一个线程更改某个共享变量。(其实没有共享变量,也不会存在并发问题),...

    多核编程中的线程分组竞争模式

    目前业界发展的无锁编程技术可以有效降低锁竞争引起的性能下降问题,无锁编程主要是采用原子操作来替代锁,只存在原子操作竞争问题,由于原子操作只是一条指令,速度非常快,因此可以近似地看成是无锁竞争的,除非...

    sspfd:sspfd 是一个超级简单的分析器,能够以单个 CPU 周期的粒度测量时序

    例如,您可以使用 sspfd 来测量获取锁或对某些数据执行原子操作的延迟。 网站: : 作者 : Vasileios Trigonakis 安装: 使用基本文件夹中的make编译库。 使用sspfd_test测试安装(使用./sspfd_test -h查看可用...

Global site tag (gtag.js) - Google Analytics