概述

数据竞争 (data race) 是指多个线程/进程同时访问一个共享资源时,最终计算结果的正确性依赖于线程/进程的执行顺序的这种现象。

举例来说,线程 t1 和线程 t2 都要对一个全局变量 int x = 0 做“自增 1“操作,而线程 t 对变量 x 做出的一个(非原子性的)自增操作实际上会被编译器分解为下列三个更细粒度的、更加“基本”的操作:

对于单线程的程序来说,这样一个简单的自增过程几乎不可能出错。然而,假如有两个线程“同时”对同一个变量做这样的自增操作,事情就不一样了:因为自增操作默认情况下不是一个原子操作,一个线程要自增一个变量它要做三件事(执行以上三条指令),如果中间有了差错,最终结果就不对,例如:

假设 int x 的初始值是 0,那么容易验证,经过上述六条指令,最终 x 的值一定是 1 而不是 2,这就是两个线程的指令以错误的执行顺序去操作一个共享资源 (int x) 导致的最终计算结果的错误。

这 6 条指令当且仅当以下列这两种顺序执行时,最终结果才是正确的:

顺序 1:

t1: ldr r0, x
t1: add r0, r0, 1
t1: str r0, x
t2: ldr r0, x
t2: add r0, r0, 1
t2: str r0, x

顺序 2:

t2: ldr r0, x
t2: add r0, r0, 1
t2: str r0, x
t1: ldr r0, x
t1: add r0, r0, 1
t1: str r0, x

换个角度解释:在多线程情形中,一个线程 t 在自增一个变量 x 的时候,为了保证最终结果的正确性,t 必须某种程度上「独占」这个变量 x。