关于int全区变量读写的原子性

    关于int变量的读写是否原子性网上有非常多讨论,貌似不同平台不同,这里自己做实如今arm9平台測试。这里要注意原子性并不是指一条汇编才原子,实际上即使一次赋值编译成几条汇编依旧能够是原子的,仅仅要保证该内存不产生中间值,仅仅有原值和目标值两种状态则就是原子的。对一个int变量赋值是否要进入临界区呢?

下面基于arm920t cpu Sourcery G++ arm-none-eabi-gcc 编译器測试int原子性:

1、正常四字节对齐的int变量和非四字节对齐的char变量
typedef struct {
char c1;
char c2;
// atomic_t i1;
int i1;
} str_t;
volatile str_t Gstr ;
int main(void)
{
Gstr.c1 = 1;
Gstr.c2 = 2;
Gstr.i1 = 0x12345678;
while (1);
return 0;
}

int main(void)
{
8000: e52db004 push {fp} ; (str fp, [sp, #-4]!)
8004: e28db000 add fp, sp, #0
Gstr.c1 = 1;
8008: e59f1030 ldr r1, [pc, #48] ; 8040 <main+0x40>
800c: e3a03001 mov r3, #1
8010: e1a02003 mov r2, r3
8014: e1a03001 mov r3, r1
8018: e5c32000 strb r2, [r3]
Gstr.c2 = 2;
801c: e59f101c ldr r1, [pc, #28] ; 8040 <main+0x40>
8020: e3a03002 mov r3, #2
8024: e1a02003 mov r2, r3
8028: e1a03001 mov r3, r1
802c: e5c32001 strb r2, [r3, #1]
Gstr.i1 = 0x12345678;
8030: e59f3008 ldr r3, [pc, #8] ; 8040 <main+0x40>
8034: e59f2008 ldr r2, [pc, #8] ; 8044 <main+0x44>
8038: e5832004 str r2, [r3, #4]
while (1);
803c: eafffffe b 803c <main+0x3c>
8040: 00010060 .word 0x00010060
8044: 12345678 .word 0x12345678

从以上汇编看,在对齐的int写操作是原子的(  8038: e5832004 str r2, [r3, #4]),仅一条str赋值指令。
char型能够通过strb对字节操作的指令一次完毕,不管是否对齐都是单指令完毕,故也是原子的。(strb的内存操作能够以字节对齐)

2、非四字节对齐的int型变量赋值
</pre><pre name="code" class="cpp">typedef struct {
char c1;
int i1;
} __attribute__((__packed__)) str_t; volatile str_t Gstr ; int main(void)
{
Gstr.c1 = 1;
Gstr.i1 = 0x12345678;
while (1);
return 0;
}
Gstr.i1 = 0x12345678;
801c: e59f3024 ldr r3, [pc, #36] ; 8048 <main+0x48>
8020: e5932000 ldr r2, [r3]
8024: e20210ff and r1, r2, #255 ; 0xff
8028: e59f201c ldr r2, [pc, #28] ; 804c <main+0x4c>
802c: e1812002 orr r2, r1, r2
8030: e5832000 str r2, [r3]
8034: e5932004 ldr r2, [r3, #4]
8038: e3c220ff bic r2, r2, #255 ; 0xff
803c: e3822012 orr r2, r2, #18
8040: e5832004 str r2, [r3, #4]
while (1);
8044: eafffffe b 8044 <main+0x44>
8048: 00010068 .word 0x00010068
804c: 34567800 .word 0x34567800
可见当int变量非四字节对齐时,将无法单指令完毕全部赋值,分两步赋值,这样就产生了中间值,即非原子。
ldr str指令要求操作地址是4字节对齐的。
(PS:从一个非对齐的int的赋值看,转成汇编须要这么多的操作,所以平时一些要求高效率的代码要考虑内存对齐问题,默认编译器都是会定义对齐内存的)

3、非四字节对齐int变量读取。
typedef struct {
char c1;
int i1;
} __attribute__((__packed__)) str_t;
volatile str_t Gstr ;
int rd;
int main(void)
{
rd = Gstr.i1;
while (1);
return 0;
}
rd = Gstr.i1;
8008: e59f3024 ldr r3, [pc, #36] ; 8034 <main+0x34>
800c: e5932000 ldr r2, [r3]
8010: e1a02422 lsr r2, r2, #8
8014: e5933004 ldr r3, [r3, #4]
8018: e20330ff and r3, r3, #255 ; 0xff
801c: e1a03c03 lsl r3, r3, #24
8020: e1833002 orr r3, r3, r2
8024: e1a02003 mov r2, r3
8028: e59f3008 ldr r3, [pc, #8] ; 8038 <main+0x38>
802c: e5832000 str r2, [r3]
while (1);
8030: eafffffe b 8030 <main+0x30>
8034: 00010054 .word 0x00010054
8038: 0001005c .word 0x0001005c

从编译结果看,非对齐int读取也是非原子的,i1被分为两部分,i1的内存被訪问两次,这样中间有可能被改动: 800c: e5932000
ldr r2, [r3]     8014: e5933004 ldr r3, [r3, #4]    读r3和r3+4 都是i1的内存,相当于分两次訪问同一变量就有可能被改动内存。

 
总结:int类型在对齐时读写是原子的(编译默认是对齐的),在非对齐时读写不是原子的。
    可參考linux中的atomic.h查看原子操作的实现。能够自己实现一个atomic函数集,当希望一个变量的操作原子性时,使用atomic来操作该变量就可以。

关于int全区变量读写的原子性的更多相关文章

  1. 假设result是一个float型变量,其值为27.32,value是一个int型变量,其值为15执行以下语句后,两个便利的值分别是多少?为什么?

    假设result是一个float型变量,其值为27.32,value是一个int型变量,其值为15执行以下语句后,两个便利的值分别是多少?为什么? 在执行这条语句的过程中,保存在result中的值被读 ...

  2. 假设result 是一个float型变量,value是一个int型变量。执行以下赋值语句以后,变量value将是什么类型?为什么?

    假设result 是一个float型变量,value是一个int型变量.执行以下赋值语句以后,变量value将是什么类型?为什么? 在执行这条语句的过程中,保存在vulue变量中的值被读取出来并转化为 ...

  3. loadrunner 脚本开发-int型变量和字符串的相互转换

    脚本开发-int型变量和字符串的相互转换 by:授客 QQ:1033553122 字符串转化为int型变量 Action2() { int j = 0; j = atoi("12345&qu ...

  4. int型变量,不使用中间变量完成互换

    package com.t_02; /** * 定义两个int类型的数,完成交换,不使用第三方变量 * @author Administrator * */ public class t1 { pub ...

  5. 007、Java中定义int型变量

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  6. 为什么声明了int型的变量并且直接初始化后,int型变量的地址一直在变化?

    /************************************************************************* > File Name: ptr_varia ...

  7. c# sql在where查询语句中使用字符串变量与int型变量

    使用where语句访问数据库时where语句用上文中以及定义过的变量来查询. string sql3 = string.Format("update Ships set ContainerN ...

  8. [转]关于int整形变量占有字节问题

    int的长度由处理器(16位,32位,64位)和比哪一期决定. 首先从处理器来讲 :16位处理器中的int 占有16位 即2个字节                         32位处理器中int ...

  9. C#知识点记录

    用于记录C#知识要点. 参考:CLR via C#.C#并发编程.MSDN.百度 记录方式:读每本书,先看一遍,然后第二遍的时候,写笔记. CLR:公共语言运行时(Common Language Ru ...

随机推荐

  1. Android编程 获取网络连接状态 及调用网络配置界面

    获取网络连接状态 随着3G和Wifi的推广,越来越多的Android应用程序需要调用网络资源,检测网络连接状态也就成为网络应用程序所必备的功能. Android平台提供了ConnectivityMan ...

  2. 使用ReactiveCocoa实现iOS平台响应式编程

    使用ReactiveCocoa实现iOS平台响应式编程 ReactiveCocoa和响应式编程 在说ReactiveCocoa之前,先要介绍一下FRP(Functional Reactive Prog ...

  3. Windows Phone开发(31):画刷

    原文:Windows Phone开发(31):画刷 画刷是啥玩意儿?哈,其实画刷是用来涂鸦,真的,没骗你,至于你信不信,反正我信了. 本文通过价绍几个典型的画刷,使你明白画刷就是用来涂鸦的. 一.纯色 ...

  4. 矩形旋转碰撞,OBB方向包围盒算法实现

    怎样进行2D旋转矩形的碰撞检測.能够使用一种叫OBB的检測算法(Oriented bounding box)方向包围盒.这个算法是基于SAT(Separating Axis Theorem)分离轴定律 ...

  5. Android应用开发-小巫CSDN博客client之显示博文具体内容

    Android应用开发-小巫CSDN博客客户端之显示博文具体内容 上篇博文给大家介绍的是怎样嵌入有米广告而且获取收益,本篇博客打算讲讲关于怎样在一个ListView里显示博文的具体信息.这个可能是童鞋 ...

  6. Android源代码下载之《Android新闻client源代码》

    介绍 Android新闻client源代码,功能上分为:新闻.关注.读报.微博.里面比較有特色的就是读报功能.真正安装报纸的排版进行读报.给人得感觉就像是在读真实的报纸.事实上即使首页的动态云标签很有 ...

  7. elasticsearch2.2

    elasticsearch2.2 集群搭建各种坑     目前生产环境的es版本是1.0版本,需要升级到最新的2.2版本,于是在测试环境进行部署集群测试,在测试过程中遇到的坑相当多,下面详细介绍下. ...

  8. javascript---在自由落体实现

    实现一些简单的物业自由落体需要理解: clientHeight:浏览器客户机的整体高度 offsetHeight:物(实例div)高低 offsetTop:从对象client最顶层的距离 简单demo ...

  9. HDU 4951 Multiplication table 阅读题

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=4951 题意:给一个P进制的乘法表.行和列分别代表0~p-1,第i行第j*2+1和第j*2+2列代表的是第i ...

  10. Java Swing TextArea 滚动条和获得焦点

    JTextArea text=new JTextArea(); text.setLineWrap(true);//设置自己主动换行,之后则不须要设置水平滚动栏 JScrollPane scroll=n ...