搜索
bottom↓
回复: 36

请问:C整形变量赋数值、++、--等是不是原子操作?

[复制链接]

出0入0汤圆

发表于 2017-5-22 19:32:11 | 显示全部楼层 |阅读模式
就是如同下面的例子:

int i;

i = 123;
i++;
i--;

诸如此类......

出0入0汤圆

发表于 2017-5-22 19:44:09 | 显示全部楼层
这个也和芯片有关系吧.

出40入42汤圆

发表于 2017-5-22 19:45:27 | 显示全部楼层
据我所知,i++和i--不是原子操作,被坑过

出0入0汤圆

发表于 2017-5-22 20:21:47 | 显示全部楼层
这题目出的不错~~
                                 

出0入0汤圆

发表于 2017-5-22 20:27:46 | 显示全部楼层
依赖于体系结构和编译器,不一定是原子操作。

出0入442汤圆

发表于 2017-5-22 20:29:14 来自手机 | 显示全部楼层
dr2001 发表于 2017-5-22 20:27
依赖于体系结构和编译器,不一定是原子操作。

一定不是。因为atom操作必须先raise内存barrier。

出0入0汤圆

发表于 2017-5-22 20:45:53 | 显示全部楼层
wye11083 发表于 2017-5-22 20:29
一定不是。因为atom操作必须先raise内存barrier。

stm8系列里用cosmic编译器, 8位和16位变量都是原子操作++ --,不会因为中断而得到中间值

出0入442汤圆

发表于 2017-5-22 20:47:34 来自手机 | 显示全部楼层
snoopyzz 发表于 2017-5-22 20:45
stm8系列里用cosmic编译器, 8位和16位变量都是原子操作++ --,不会因为中断而得到中间值 ...

这操作是单指令周期的。。。不涉及分拆

出0入0汤圆

发表于 2017-5-22 20:52:21 | 显示全部楼层
wye11083 发表于 2017-5-22 20:47
这操作是单指令周期的。。。不涉及分拆

对呀, 所以别说一定不是...要分具体芯片, 变量情况 , 编译器

出0入0汤圆

发表于 2017-5-22 20:55:36 | 显示全部楼层
wye11083 发表于 2017-5-22 20:29
一定不是。因为atom操作必须先raise内存barrier。

呵呵,不要那么绝对。
简单MCU核,非Load/Store的,不一定有那么复杂。

E.g. C51,INC/DEC @Ri,间址直接操作idata。

出40入42汤圆

发表于 2017-5-22 20:57:53 | 显示全部楼层
楼上说的对,我被坑的是ARM的32位处理器的编译器

出0入93汤圆

发表于 2017-5-23 06:43:33 | 显示全部楼层
落叶知秋 发表于 2017-5-22 20:57
楼上说的对,我被坑的是ARM的32位处理器的编译器

哈哈,什么叫高级精简指令集?就是比一般精简指令集还要高级,看起来理所当然的东西到这里并不完全适用,可能会给拆得七零八落。
一个简单的自增,可能都需要先LDR地址,然后LDR或MOV数据,然后++,然后STR数据。要是没有专门的访问指令访问非32位的变量,还有额外的逻辑操作。要是硬件不支持非对齐访问,软件访问非对齐数据时额外加的东西就更多了,反汇编出来一大片。

出0入0汤圆

 楼主| 发表于 2017-5-23 08:08:23 | 显示全部楼层
落叶知秋 发表于 2017-5-22 20:57
楼上说的对,我被坑的是ARM的32位处理器的编译器

我用的是cortex  M3 内核,请问有什么办法?

比如在主程序和中断中都要操作某个全局变量。

出0入0汤圆

发表于 2017-5-23 08:30:24 | 显示全部楼层
C语言是不保证原子性的,最好的办法是看汇编

出0入0汤圆

 楼主| 发表于 2017-5-23 08:35:48 | 显示全部楼层
zhugean 发表于 2017-5-23 08:30
C语言是不保证原子性的,最好的办法是看汇编

没错

可是我是希望能用C语句来保证全局变量互斥操作

请问有没有办法?

出0入8汤圆

发表于 2017-5-23 08:39:20 | 显示全部楼层
prince2010 发表于 2017-5-23 08:08
我用的是cortex  M3 内核,请问有什么办法?

比如在主程序和中断中都要操作某个全局变量。 ...

进入中断临界区。

出40入42汤圆

发表于 2017-5-23 08:59:26 | 显示全部楼层
prince2010 发表于 2017-5-23 08:08
我用的是cortex  M3 内核,请问有什么办法?

比如在主程序和中断中都要操作某个全局变量。 ...

看以前讨论过这个技术问题的帖子吧:
https://www.amobbs.com/forum.php?mod=viewthread&tid=5664521

出0入0汤圆

发表于 2017-5-23 09:51:00 | 显示全部楼层
这个帖子不错,我也一直思考这个问题

出0入0汤圆

 楼主| 发表于 2017-5-23 10:05:46 | 显示全部楼层
security 发表于 2017-5-23 08:39
进入中断临界区。

具体怎么搞?
STM32,M3内核

出0入8汤圆

发表于 2017-5-23 12:00:19 | 显示全部楼层
prince2010 发表于 2017-5-23 10:05
具体怎么搞?
STM32,M3内核

就是:volatile + 关开中断。
我之前说的可能文绉绉了。

出0入0汤圆

发表于 2017-5-23 12:29:08 | 显示全部楼层
prince2010 发表于 2017-5-23 08:35
没错

可是我是希望能用C语句来保证全局变量互斥操作

据我的了解,cm3的8、32bit变量操作就是天生就是原子的

出5入14汤圆

发表于 2017-5-23 12:47:03 | 显示全部楼层
楼主这个显然主要跟芯片有关系、然后是编译器!
首先得看编译器把这个变量存哪里,然后得看芯片有没有直接指令支持对这个RAM增一或减一的操作。

出0入8汤圆

发表于 2017-5-23 13:09:57 来自手机 | 显示全部楼层
现在的处理器还有cache,多核之类的
就算是能够用一条指令对内存进行++,--运算
也得看是不是真的“落在了”那片内存上

出0入0汤圆

发表于 2017-5-23 14:58:06 | 显示全部楼层
与芯片有关。也与编译器有关。与数据类型也有关。

出0入0汤圆

发表于 2017-5-23 16:56:10 | 显示全部楼层
原子的操作的实现是有的,叫做LOCK-FREE,基本上就是基于CAS或者 Fetch And xxx来实现的。很多编译器和CPU架构对原子操作都有实现。比如GCC里面的__sync_add_and_fetch和__sync_sub_and_fetch,这两个就是原子性的加1和减1。 windows平台的Interlocked系列,比如InterlockedAdd就是原子性的加1.还有C++的STL里面atomic类。

出0入0汤圆

发表于 2017-5-23 17:11:55 | 显示全部楼层
另外ARM系列也有atomic系列的函数。有些ARM架构的atomic实现里面就有开关中断,有些架构的实现就不会开关中断。比如M0,M3,M4的实现:

#define ATOMIC_OP(asm_op, a, v) do {                                \
        uint32_t reg0;                                                \
                                                                \
        __asm__ __volatile__("   cpsid i\n"                        \
                             "   ldr  %0, [%1]\n"                \
                             #asm_op" %0, %0, %2\n"                \
                             "   str  %0, [%1]\n"                \
                             "   cpsie i\n"                        \
                             : "=&b" (reg0)                        \
                             : "b" (a), "r" (v) : "cc");        \
} while (0)

static inline void atomic_add(uint32_t volatile *addr, uint32_t value)
{
        ATOMIC_OP(add, addr, value);
}
static inline void atomic_sub(uint32_t volatile *addr, uint32_t value)
{
        ATOMIC_OP(sub, addr, value);
}

这里就看出这样的好处是多并发的程序不需要频繁的开关中断和lock/unlock,会有很大的性能提升。同样可以看出,指令上还是有开销的。

出0入0汤圆

发表于 2017-5-23 18:22:49 来自手机 | 显示全部楼层
flamma 发表于 2017-5-23 16:56
原子的操作的实现是有的,叫做LOCK-FREE,基本上就是基于CAS或者 Fetch And xxx来实现的。很多编译器和CPU ...

好像就是这个,可以贴贴实现代码,用了互斥访问指令

出0入0汤圆

 楼主| 发表于 2017-6-1 16:28:58 | 显示全部楼层
security 发表于 2017-5-23 12:00
就是:volatile + 关开中断。
我之前说的可能文绉绉了。

是这两个吗——

        __set_PRIMASK(1);//关总中断

        __set_PRIMASK(0);//开总中断



出0入8汤圆

发表于 2017-6-1 18:17:50 | 显示全部楼层
prince2010 发表于 2017-6-1 16:28
是这两个吗——

        __set_PRIMASK(1);//关总中断

是的。。

出0入0汤圆

 楼主| 发表于 2017-6-1 19:22:34 | 显示全部楼层

出0入0汤圆

 楼主| 发表于 2017-6-1 19:49:03 | 显示全部楼层
落叶知秋 发表于 2017-5-22 19:45
据我所知,i++和i--不是原子操作,被坑过

不知道你是怎么被坑的,可以发个例程吗?

出0入20汤圆

发表于 2017-6-2 08:40:28 | 显示全部楼层
这个问题20多年前就谈论过,反汇编看看代码就知道了。

出0入4汤圆

发表于 2017-6-2 08:48:21 | 显示全部楼层
做临界代码保护吧,一般人多掉过这个坑

出0入4汤圆

发表于 2017-6-2 08:53:49 | 显示全部楼层
在AVR的年代,读16bit的数据是多周期的,由于读取中断变量没有做临界保护,掉过一次坑,

出0入0汤圆

 楼主| 发表于 2017-6-2 09:24:15 | 显示全部楼层
chendaon 发表于 2017-6-2 08:48
做临界代码保护吧,一般人多掉过这个坑

可是这种现象又不好复现.

出0入0汤圆

 楼主| 发表于 2017-6-2 09:29:42 | 显示全部楼层
mon51 发表于 2017-6-2 08:40
这个问题20多年前就谈论过,反汇编看看代码就知道了。

仿真看了一下,一个++操作确实对应有好几条汇编语句......

出0入0汤圆

发表于 2017-6-2 09:44:34 | 显示全部楼层
mon51 发表于 2017-6-2 08:40
这个问题20多年前就谈论过,反汇编看看代码就知道了。

赞!!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-30 17:46

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表