在中断程序内 变量的加加,这种情况是否会出现BUG!

2019-12-27 19:02发布

先说明一下   a=a+1这条程序语句的执行步骤:
javascript:;

我在想这种情况:
如果执行到第一步,将a的值读到寄存器R中

执行完这一条后,来了个中断就是 a=a-1 !
等执行完 a=a-1 ,这时候重点来了!

我的CPU会回到 a=a+1 的第二步!
R寄存器里面是不知道 a 已经被改变了,所以他还是按照原先的值 加1!
然后在写回到 a !
  
这时候就会出现bug了!
这种情况大伙们有考虑过吗?  要怎么避免?
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
84条回答
knight_sh
1楼-- · 2020-01-05 15:57
redroof 发表于 2016-12-8 09:04
我贴一个完整的无锁队列来终结讨论吧。
这是真正完整的代码。模板参数buflen是队列缓存的长度,T是队列里 ...

代码没仔细看,但是看到%操作就非常不爽了,:)
一般环形缓冲区的大小len设置成2的N次幂,那么mask = len - 1,读写指针的位置 index = wr(或rd) & mask;
另外在有些系统中需要通过内存屏障来保障数据完整性(读写指针偏移一定是数据已写入/读取后才操作的)。
redroof
2楼-- · 2020-01-05 20:19
knight_sh 发表于 2016-12-8 09:27
代码没仔细看,但是看到%操作就非常不爽了,:)
一般环形缓冲区的大小len设置成2的N次幂,那么mask = le ...

编译器不笨的。
模板参数是编译时常量,如果是2的整数次方会自动优化。其实除以其它的小整数也都会有对应的优化,你不必操心这种小事。我这么写了很多年了。
因为这是库,也不能硬性指定必须是2的整数次方。别人要4K个缓存如果还欠一点,难道必须加到8K?太浪费了。
redroof
3楼-- · 2020-01-05 21:17
knight_sh 发表于 2016-12-8 09:27
代码没仔细看,但是看到%操作就非常不爽了,:)
一般环形缓冲区的大小len设置成2的N次幂,那么mask = le ...

另,这个队列对指针的操作是有讲究的,进函数的时候读它,然后用这个指针去读/写数据,然后把指针加一,再写回。
这个顺序是精确考虑过的。指针写回是最后一步,这个时候数据已经读/写完毕。别处见到指针的新值就表示这个数据项已经完整了。
因此无需额外的内存屏障指令。
hdxet
4楼-- · 2020-01-05 23:15
讨论的很热闹,受教不少
helislayer
5楼-- · 2020-01-06 03:42
 精彩回答 2  元偷偷看……
helislayer
6楼-- · 2020-01-06 08:12
redroof 发表于 2016-12-8 07:51
简单的无锁队列只有一个读一个写。我认为这是不需要说的。用的人都知道。还有,计数器不能超过你cpu位数 ...

这个前提还是要仔细考量和强调的。
例如这个如果是个串口的 write。你如果在两个级别的中断
里面分别有两个打印串口,就会出现不小心引入多个producer
的情况。或者主程序和中断分别有写串口。这些都很容易犯
的错误。出错起来经常很莫名其妙,所以要份外小心。

溢出是一个现实问题,和计数器超过和 cpu 位数没有关系。
这个关键是代码没有检查剩余空间就写入是很不好的。

一周热门 更多>