http://software.intel.com/zh-cn/blogs/2010/01/14/cpucpu/?cid=sw:prccsdn956

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

硬件级的原子操作:     在单处理器系统(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动不了.

from:

http://blog.csdn.net/microtong/archive/2010/01/20/5211750.aspx

posted on 2010-04-03 21:05 chatler 阅读(1081) 评论(0)  编辑 收藏 引用 所属分类: C++_BASIS

c语言原子操作实例,多CPU上的原子操作相关推荐

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

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

  2. c语言vc6.0界面设计实例,vc6.0使用简介及C语言在6.0平台上的编程实例.ppt

    vc6.0使用简介及C语言在6.0平台上的编程实例 C++ 目录 第一章:Visual C++概述 第二章:C++语言基础 第三章:用MFC编写Windows程序 第四章:消息与输入 第五章:菜单.工 ...

  3. 面试官:Java如何绑定线程到指定CPU上执行?

    不知道你是啥感觉,但是我第一次看到这个问题的时候,我是懵逼的. 而且它还是一个面试题. 我懵逼倒不是因为我不知道答案,而是恰好我之前在非常机缘巧合的情况下知道了答案. 我感觉非常的冷门,作为一个考察候 ...

  4. FastFormers:实现Transformers在CPU上223倍的推理加速

    点击上方,选择星标或置顶,不定期资源大放送! 阅读大概需要5分钟 Follow小博主,每天更新前沿干货 作者:Parth Chokhra 编译:ronghuaiyang 导读 使用多头注意力的Tran ...

  5. c语言220程序,《C语言程序实例大全》原代码220例

    <C语言程序实例大全>,一共220个. 找了很多地方都不全,最后在CSDN上用积分下载了这个,C语言初学者可以参考. 下载地址: http://doc.xuehai.net/tp09770 ...

  6. 多核CPU上python多线程并行的一个假象(转)

    转自:http://www.cnblogs.com/skying555/p/6527189.html GIL 与 Python 线程的纠葛 GIL 是什么东西?它对我们的 python 程序会产生什么 ...

  7. mysql中dml操作_MySQL的DML语言操作实例

    补充说明,外键:不要使用外键,一切外键概念都在应用层解决. 补充说明,数据库的列,也就是字段名,尽量带上飘符号` 数据库存在的意义:数据存储和数据管理. 数据库:行(数据),列(字段) 注意:本页是解 ...

  8. 【Golang第8章:面向对象编程】Go语言的结构体是什么,怎么声明;Golang方法的调用和声明;go语言面向对象实例,go语言工厂模式;golang面向对象的三大特性:继承、封装、多态

    介绍 这个是在B站上看边看视频边做的笔记,这一章是Glang面向对象编程 这一章内容较多,内容有Go语言的结构体是什么,怎么声明:Golang方法的调用和声明:go语言面向对象实例,go语言工厂模式: ...

  9. qt 飞扬青云_R语言学习——实例标识符

    > patientID > age > diabetes > status > patientdata > #在上述创建的病例数据框中,病人编号(patientID ...

最新文章

  1. LeetCode简单题之最近的请求次数
  2. Mac OS X 10.8.5 安装编译glib
  3. .mdf 如何导入到sqlyog_FLASH如何实例游戏中的音效控制(AS3)
  4. SQLite Select 语句(http://www.w3cschool.cc/sqlite/sqlite-select.html)
  5. 第六章 设计程序架构 之 设计实现WebSocket策略
  6. echarts 获取点击的y轴数值_有机磷酸催化对醌的不对称直接加成反应合成轴手性芳基醌类化合物...
  7. 文青不适合看的电影《雪国列车》
  8. jQuery框架学习第十天:实战jQueryUI常用功能
  9. 创业奇才:才3年5000元变600万
  10. 力扣501. 二叉搜索树中的众数(JavaScript)
  11. fanuc机器人编程手册_FANUC机器人示教编程:距离先执行指令功能介绍与使用方法
  12. 安徽大学计算机科学与技术学院刘峰,刘峰
  13. linux网络子系统分析(三)—— 设备无关层
  14. Node.js 4493图片批量下载爬虫1.00
  15. Python绘制正态分布图及求分位数
  16. R语言各种假设检验实例整理(常用)
  17. python怎么降序输出结果_按降序打印Python
  18. 教你解决微信跳转appstore的困扰
  19. 三个指标怎么做分层图_分层性能指标以及在哪里找到它们
  20. JAVA线程池 -clt设计与分析

热门文章

  1. RISC-V SiFive U64内核——HPM硬件性能监视器
  2. 大数据架构师拿年薪50W的方法诀窍
  3. PostgreSQL 使用RETURNING返回值
  4. AI实战:深度学习模型压缩:模型裁剪——Pruning with Keras
  5. 2022济南大学acm新生赛题解
  6. 解决微信(扫码)无法直接下载apk的问题
  7. U盘启动安装CentOS Linux系统
  8. 安装黑群晖不求人,arpl在线编译安装群晖教程
  9. IPV4地址和子网理解
  10. 清华大学立功了!“破冰”芯片核心技术