关于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. 关于java mail 发邮件的问题总结(转)

    今天项目中有需要用到java mail发送邮件的功能,在网上找到相关代码,代码如下: import java.io.IOException; import java.util.Properties; ...

  2. zoj 3822 Domination(2014牡丹江区域赛D称号)

    Domination Time Limit: 8 Seconds      Memory Limit: 131072 KB      Special Judge Edward is the headm ...

  3. spring整合flex

    在常规的开发中只是用flex二不和后台交互是不可能的,为此flex也提供了和后台交互的2种解决方案一种是Data Services另一种是BlazeDs,本篇博客是用的是后一种,我的开发步骤如下: 1 ...

  4. 高速幂 POW优化

    #include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h&g ...

  5. centos 64位编译安装 glibc-2.14

    cd /opt wget http://ftp.gnu.org/gnu/glibc/glibc-2.14.tar.gz tar -xzf glibc-2.14.tar.gz cd glibc-2.14 ...

  6. Windows IOT

    Windows IOT 开发入门(准备工作)   终于抽出空来了,将最近研究的东西记录下来,物联网,万物皆可联网.然后可以做到智能家居,智能生活,智能城市....一大堆.吹牛的就不说了. 在实际应用中 ...

  7. #Windows Phone:在HTML5专案中,如何从Javascript传送字串到C#的APP端

    原文:#Windows Phone:在HTML5专案中,如何从Javascript传送字串到C#的APP端 #Windows Phone:在HTML5专案中,如何从Javascript传送字串到C#的 ...

  8. 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 ...

  9. Win32 Windows编程 九

    资源的使用 1 资源文件 图标 光标 字符串 菜单  加速键 对话框资源位图等等 资源脚本文件 - 扩展名为RC文件 定义了资源和相关文件等信息 资源编译器 - RC.exe 2 图标资源 ICON ...

  10. 采用ACE登录设施(一)HelloWorld

    (1)开始使用日志设施 使用日志设施,总是要包括头文件: #include "ace/Log_Msg.h" ACE日志的Hello World #ifdef _DEBUG #pra ...