对于全局变量区域,不同的任务(线程)可能会访问变量区的同一变量,这种对于同一内存访问的情况,就是并发情况。而对于这种并发的问题,会引入竞争。
int a = 1; a++;
对于全局变量int a,对于其操作加1操作。
假设有两个或者两个以上的线程A,线程B。在这两个线程中,都会对全局变量a做加1操作。
如上所示,在C语言中a++的操作,在实际的执行过程中,大概是执行右侧四条汇编指令。
第一步:先获取变量a的地址,并将其存储在r1的寄存器。
第二步:将a变量值读取到r0寄存器中。
第三步:执行加1操作。
第四步:把计算值存放在a的地址。
情况1(正常情况)
线程A与线程B都会执行对变量a执行加1操作。如果线程A与线程B次序执行(所谓次序执行,线程A执行完加1操作之后,线程B再执行加1操作)。
当线程A执行完a++操作之后,此时a的值变成2。
后面线程B继续执行a++操作,执行之后,a的值变成3。
这样,经过线程A与线程B操作之后,a的值变成3。(符合期望)。
情况2(异常情况)
如上图所示,在执行a++操作(add r0,#1),线程A被线程B抢占。此时,OS会保存线程A的线程,具体来说就是将R0~R15寄存器的值保存在线程A的栈中,
学术称为保存现场。注意此时a的值仍为1,而且线程r0的值仍为1。
保存现场之后,开始线程B。对a执行加1操作。如图中黄色曲线所示,执行完之后,a的值变成2。
恢复线程A的现场,此时r0的值恢复为1。从蓝色曲线的红色处继续执行,而r0的值加1,r0的值变成2,将其存储在a的地址,此时a=2(异常)。
备注:执行结果异常的原因是,执行a++操作被打断,抢占。解决该问题,需要引入原子操作(下篇总结)。就是执行原子操作的语句,不能被打断。
一条C语言,被转换为4条汇编指令执行,这个是Arm的指令体系所决定的,具体可以来接Arm的体系架构。