竞态条件
什么是竞态条件?
当设备或系统试图同时执行两个或多个操作时,竞态条件是一种不希望出现的情况,但由于设备或系统的性质,这些操作必须按照正确的顺序执行才能正确地执行。
竞争条件通常与计算机科学和编程有关。当两个计算机程序进程或线程试图在同一时间访问相同的资源并在系统中引起问题时,就会发生这种情况。
竞争条件被认为是多线程应用程序的一个常见问题。
竞态条件的例子有哪些?
竞态条件的一个简单例子是电灯开关。在一些家庭里,一个普通的顶灯上连着多个电灯开关。当这些类型电路使用时,开关位置变得无关紧要。如果灯是亮的,从其当前位置移动任何一个开关将关闭灯。同样,如果灯是关着的,那么从当前位置移动任何一个开关就会打开灯。
考虑到这一点,想象一下如果两个人同时用两个不同的开关开灯会发生什么。一个指令可能取消另一个或两个动作可能跳闸。
在计算机内存或存储器中,如果几乎在同一时刻接收到读写大量数据的命令,并且机器试图在读取旧数据时覆盖部分或全部旧数据,则可能发生竞态条件。结果可能是下列一个或多个:
- 计算机崩溃或识别出程序的非法操作
- 读取旧数据时出错
- 写入新数据时出错
如果以错误的顺序处理指令,也可能发生竞态条件。
假设两个进程需要执行一个bit翻转在特定的内存位置。在正常情况下,操作应该如图1所示。
如果发生竞争条件,导致这两个进程重叠,操作序列可能更像图2所示。
竞争条件偶尔发生在逻辑门当输入发生冲突时。因为门输出状态需要有限的、非零的时间来对输入状态的任何变化作出反应,跟随门的敏感电路或设备可能被输出状态愚弄而不能正常工作。
竞争条件的类型是什么?
竞争条件有几种类型。定义竞争条件对系统影响的两种类型被称为临界和非临界:
- 一个至关重要的竞争条件将导致设备、系统或程序的结束状态改变。例如,如果同时拨动连接在一盏普通灯上的两个电灯开关会损坏电路,这就被认为是一个临界竞争条件。在软件中,临界竞争条件是当一种情况导致不可预测或未定义的行为的bug。
- 一个被竞态条件不会直接影响系统、设备或程序的结束状态。在灯的例子中,如果灯是关闭的,同时拨动两个开关就会打开灯,效果与拨动一个开关相同,那么这就是一个非关键竞争条件。在软件中,非临界竞争条件不会导致错误。
关键和非关键竞争条件并不局限于电子或编程。它们可以发生在发生竞争条件的许多类型的系统中。
在编程中,两种主要的竞态条件发生在代码的临界段,即由多个线程执行的代码段。当多个线程试图读取一个变量,然后每个线程都对其进行操作时,可能会出现以下情况之一:
- 读-修改-写。当两个进程在一个程序中读取一个值并回写一个新值时,就会发生这种竞争条件。它经常会导致软件错误。与上面的示例一样,预期两个进程将顺序发生——第一个进程生成它的值,然后第二个进程读取该值并返回另一个不同的值。
例如,如果检查顺序处理一个支票账户,系统将确保有足够的资金在账户过程中检查,然后看一遍,看是否有足够的资金来处理检查B处理后检查a。然而,如果两个检查同时进行处理,系统可能对两个流程读取相同的账户余额值,但给出的账户余额值不正确,导致账户透支。
- act。当两个进程检查一个值,并在其上执行一个外部操作时,就会发生这种竞争条件。两个进程都检查值,但只有一个进程可以使用该值。以后发生的进程将把这个值读为null。这将导致一个可能过时或不可用的观察结果,用于确定程序下一步要做什么。例如,如果一个地图应用程序同时运行两个需要相同位置数据的进程,其中一个将先获取该值,这样另一个就不能使用它。后面的进程将数据读取为空。
竞争条件会导致哪些安全漏洞?
一个被设计成按特定顺序处理任务的程序,如果被要求同时执行两个或多个操作,就会遇到安全问题。威胁参与者可以利用从启动服务到安全控制生效之间的时间间隔来创建死锁或线程阻塞情况。
死锁漏洞是一种严重的拒绝服务脆弱性。当两个或多个线程必须相互等待以获得或释放循环链中的锁时,可以使其发生。这种情况会导致死锁,整个软件系统会停止运行,因为如果链是循环的,就无法获得或释放这些锁。
线程块还会极大地影响应用程序的性能。在这种类型的并发缺陷中,一个线程调用一个长时间运行的操作,同时持有锁并阻止其他线程的进程。
如何识别比赛条件
检测和识别竞争条件被认为是困难的。它们是由代码中的许多可能的缺陷引起的语义问题。最好从一开始就以防止这些问题的方式设计代码。
程序员使用动态和静态分析工具来识别竞争条件。静态测试工具在不运行程序的情况下扫描程序。然而,他们产生了许多虚假的报告。动态分析工具有更少的错误报告,但它们可能无法捕获不在程序中直接执行的竞争条件。
竞争条件有时是由数据竞争产生的,当两个线程并发地针对同一内存位置并且至少有一个是写操作时,就会发生数据竞争。数据竞争比竞争条件更容易检测,因为它们需要特定的条件才能发生。工具,比如Go项目的数据竞赛检测器,监视数据竞争情况.竞态条件与应用程序语义联系更紧密,并带来更广泛的问题。
如何防止竞态条件?
两种程序员可以防止操作系统和其他软件中的竞态条件的方法包括:
- 避免共享状态.这意味着检查代码,以确保当共享资源是系统或进程的一部分时,原子操作是独立于其他进程运行的,并且使用锁定来强制代码关键部分的原子操作。不可变对象也可以使用一旦创建就不能更改的对象。
- 使用线程同步.在这里,程序的给定部分一次只能执行一个线程。
防止竞争条件与其他类型的技术也是可能的:
存储和内存
内存或存储访问的串行化也将防止竞争条件。这意味着,如果读取和写入命令被紧密接收,默认情况下,读取命令将首先执行并完成。
网络
在一个网络,如果两个用户试图访问通道在同一时刻,两台计算机都没有收到通知,在系统授予访问权限之前通道已被占用。统计上,这种情况大多发生在延迟时间长的网络中,比如那些使用地球同步卫星.
为了防止这样的竞争条件,必须设计一个优先级方案,让一个用户独占访问。例如,当两个订阅者试图在规定的时间增量内访问系统时,其用户名或数字以字母表的前一个字母或后一个数字开头的订阅者可能获得优先级。
的外卖
竞争条件以多种方式出现在软件、存储、内存和网络中。对它们进行主动监控和预防是软件和技术设计和开发的关键部分。
防止竞态条件特别重要,因为黑客可以利用竞态条件漏洞获得对网络的未经授权访问。一个值得注意的基于竞态条件的漏洞示例被调用肮脏的牛,它利用Linux内核内存子系统中的一个缺陷来创建一个竞争条件,攻击者在此条件下获得只读内存映射的写特权。