在并发编程的情况下,“数据种族”和“竞争条件”是否是同一事物?
我经常发现这些术语在并发编程的环境中使用。 他们是相同的还是不同的?
不,他们不是一回事。 它们不是彼此的子集。 它们既不是必要的也不是充分的条件。
数据竞赛的定义非常清晰,因此,它的发现可以是自动的。 当来自不同线程的2个指令访问相同的存储器位置时,会发生数据竞争,这些访问中的至less一个是写入,并且在这些访问之间不存在任何特定顺序的同步。
竞赛条件是一个语义错误。 这是发生在导致错误程序行为的事件的时间或顺序上的缺陷。 数据竞赛可能导致很多竞争条件,但这不是必要的。
考虑下面这个简单的例子,其中x是一个共享variables:
Thread 1 Thread 2 lock(l) lock(l) x=1 x=2 unlock(l) unlock(l)
在这个例子中,线程1和2对x的写操作受锁的保护,因此它们总是按照在运行时获取锁的顺序强制执行。 也就是说,写的primefaces性不能被破坏; 在任何执行过程中两个写入之间的关系总是存在的。 我们无法知道哪个写先于另一个事先发生。
写入之间没有固定的顺序,因为locking不能提供这个。 如果程序的正确性受到影响,比如在线程2写入x之后写入线程1的x,我们说有竞争条件,尽pipe技术上没有数据竞争。
检测竞争情况比数据竞赛更有用; 然而这也是很难实现的。
构build相反的例子也是微不足道的。 这个博客文章也很好地解释了这个差异,用一个简单的银行交易的例子。
根据维基百科的说法,从第一个电子逻辑门的时代开始,“竞态条件”一直在使用。 在Java的上下文中,竞争条件可以涉及任何资源,例如文件,networking连接,线程池中的线程等。
术语“数据竞赛”最好是由JLS定义的特定含义保留。
最有趣的情况是与数据竞赛非常相似的竞争条件,但仍然不是一个,就像这个简单的例子:
class Race { static volatile int i; static int uniqueInt() { return i++; } }
由于i
是波动的,没有数据竞赛。 然而,从程序正确性angular度来看,由于两个操作的非primefaces性,存在竞争条件:读i
,写i+1
。 多个线程可以从uniqueInt
接收相同的值。
对我来说数据竞赛是所有比赛条件的一个子集。 当两个或更多的线程访问相同的内存而没有正确的locking会导致意外的值(如果你至less有一个线程正在执行写操作)时,数据竞争就会发生。
Race条件一般也可以指代线程,例如由于线程调度中的种族偶然死锁(以及不正确使用locking机制)。
不,他们是不同的,他们都不是一个子集 ,反之亦然。
术语竞争条件通常与相关的术语数据竞赛相混淆,当没有使用同步来协调对共享的非最终目标的所有访问时,会出现这种情况。 如果一个线程写入一个可能被另一个线程读取的variables,或者在两个线程都不使用同步的情况下读取一个可能最后被另一个线程写入的variables,则会冒数据竞争的风险。 在Java内存模型下,具有数据竞争的代码没有有用的定义语义 。 并非所有的竞争条件都是数据竞争,并不是所有的数据竞争都是竞争条件 ,但它们都可能导致并发程序以不可预知的方式失败。
从优秀的书–Java并发实践中由Joshua Bloc h