竞争冒险(race hazard)又名竞态条件竞争条件(race condition),它旨在描述一个系统或者进程的输出依赖于不受控制的事件出现顺序或者出现时机。此词源自于两个信号试着彼此竞争,来影响谁先输出。

举例来说,如果计算机中的两个进程同时试图修改一个共享内存的内容,在没有并发控制的情况下,最后的结果依赖于两个进程的执行顺序与时机。而且如果发生了并发访问冲突,则最后的结果是不正确的。

竞争冒险常见于不良设计的电子系统,尤其是逻辑电路。但它们在软件中也比较常见,尤其是有采用多线程技术的软件。

实例 编辑

  1. 计算机存储器或者磁盘设备里,如果同时发出大量数据指令的时候,竞争冒险可能发生。计算机尝试覆盖相同或者旧的数据,而此时旧的数据仍在被读取。结果可能是下面的一个或者多个情况:机器死机、出现非法操作并退出程序、错误的读取旧数据、或者错误的写入新数据。
  2. 网络上,竞争冒险会在:多用户同时试图访问同一个可用消息沟道时,产生。在系统同意访问前没有计算机能得到消息沟道被占用的提醒。统计上说这种情况通常发生在极端长延迟时间的网络里,譬如地球同步卫星。解决之道是用户预先产生优先级列表。然而黑客可以利用这种竞争冒险获取非法访问网络的权利。
  3. 数字电路,由于逻辑部件输出对输入有一个响应延迟,因此可能在输出上出现一个不希望有的脉冲信号。被称为Electronics glitch。使用卡诺图以发现并消除这类问题。
 
逻辑电路中的竞态条件.这里,∆t1与∆t2表示逻辑单元的传播延迟.当输入值(A)改变,电路输出有一个很短的峰持续(∆t1+∆t2) - ∆t2 = ∆t1.

软件设计 编辑

当软件具有同时执行的多个代码路径时,该软件中就可能会发生竞争。如果代码路径执行所花费的时间与预期不同,它们的执行顺序也可能会与预期不同。此类意外行为将可能导致软件错误。两个程序之间也可能发生竞争,从而导致安全隐患(见下文)。

严重的竞争将可能导致无效的运行与程序错误。当进程/线程依赖于某些共享的状态时,通常会发生严重的竞争事件。在临界区块中对共享状态的操作必须互斥。不遵循此规范可能会污染共享的状态。

数据竞争是竞争危害的一种,也是许多内存模型关注的重点部分。C11C++11标准所定义的内存模型规定含有数据竞争情况的C或C++程序带有未定义行为[1][2]

竞争可能会难以复现/调试,因为取决于干扰线程的相对执行时机,其产生的结果是非确定性的。当在调试模式下运行、附加额外的日志记录或调试器时,问题可能不会出现。这种在调试期间消失的错误通常被称为海森堡bug。因此,最好在设计环节多加注意以避免出现竞争。

示例 编辑

假设有两个线程,各自会将同一个全局数值变量加1。理想状态下,它们会以这样的顺序执行:

线程1 线程2 数据值
0
读取(0) 0
增加(1) 0
写回 1
读取(1) 1
增加(2) 1
写回 2

在上文的理想状态下,运行的结果为预期的2。但是,如果两个线程在没有锁定或通过信号量同步的情况下同时运行,执行的结果将可能出错。如下展示了另一种情况:

线程1 线程2 数据值
0
读取(0) 0
读取(0) 0
增加(1) 0
增加(1) 0
写回 1
写回 1

在这种情况下,因为线程的增加操作没有互斥,导致最终结果为1,而不是预期的2。

参见 编辑

外部链接 编辑

  1. ^ ISO/IEC 9899:2011 - Information technology - Programming languages - C. Iso.org. [2018-01-30]. (原始内容存档于2011-12-27). 
  2. ^ ISO/IEC 14882:2011. ISO. 2 September 2011 [3 September 2011]. (原始内容存档于2013-01-29).