1

我从Everything2.com采用如下竞争条件定义:

竞争条件是运行多个并发进程的情况(出于这些目的,一个线程也被建模为一个进程,就像在不同机器上运行的进程一样)将给出不同的结果,具体取决于(未指定的,通常是未指定的)细节操作的顺序。

现在考虑第 3 章中的以下示例:竞争条件和互斥

然而,最危险的竞争条件涉及对共享数据结构的访问。如果两个线程同时更新相同的数据结构,则更改可能部分由一个线程进行,部分由另一个线程进行。然后数据结构的内容可能会变得乱码,这将混淆稍后访问它的线程,从而导致它们崩溃。

显然,该样本包含有害的竞争条件。

有一种解决方案可以避免这种有害的竞争条件:

诀窍是强制线程一次访问一个数据结构,即所谓的互斥,这样每个线程都可以完成其更新并使结构保持一致状态以供下一个线程使用。

现在根据上述定义,上述解决方案中仍然存在竞争条件:

如果线程A先改变,那么共享数据结构的最终内容由线程B填充;如果线程 B 先进行更改,则共享数据结构的最终内容由线程 A 填充。

但现在它是一种无害的竞争条件。

从这个样本中,我得到以下结论:

竞争条件是有害的当且仅当它是可以避免的。

我不确定上述结论的两个方向或一个方向是否正确。那么有没有样本可以反驳这个结论呢?

4

3 回答 3

2

你说的对。

竞争条件 - 当多个线程访问相同的资源时出现。
导致竞争条件的代码段称为临界区。请注意,当我们试图避免竞争条件时会发生死锁。

您可以通过创建线程安全代码来避免竞争条件。

  • 局部变量。

    局部变量存储在每个线程自己的堆栈中。这意味着局部变量永远不会在线程之间共享。

  • 本地对象引用。

    所有对象都存储在共享堆中,但如果本地创建的对象从不逃避创建它的方法,那么它是线程安全的。

  • 使成员字段可变、最终和私有。

但是,如果您想共享一个变量并仍然以同步方式控制它的访问。您可以通过以下方式做到这一点,

  • 使用显式锁(和条件变量)
  • 使用同步(隐式锁)

这仍然不能保证哪个线程首先获得访问权,然后哪个线程获得访问权。对于这样的线程控制使用信号。

它可以通过多种方式实现。

  • 通过共享对象发送信号
  • 忙等
  • wait()、notify() 和 notifyAll()
  • 错过的信号
  • 虚假唤醒
于 2012-08-30T06:53:28.883 回答
1

您在这里错过了非常重要的一点。对数据结构的任何操作都在几个周期内发生,例如,另外给出一个非常基本的步骤,

step 1. 检索变量的当前值 step 2. 将所需的数字添加到变量的值 step 3. 存储变量的值

在寄存器级别,您可以看到更多的步骤。但关键是,通过锁定变量/数据结构的访问来避免竞争条件意味着只有一个线程可以读取/写入该数据结构。不允许其他线程读取数据结构,一旦第一个线程完成所有循环,它将允许其他线程进行更改。

如果数据结构没有被任何人锁定,线程所做的第一件事就是获取锁。然后它做读/写的东西。

所以,如果你正确地实现锁,就不应该有任何竞争条件。

竞争条件存在于两个或多个线程可以对同一数据结构进行更改时,如果不通过锁或其他机制避免这种情况,则可能是有害的。

于 2012-08-30T04:22:26.293 回答
0

我不同意。当你不想改变时,改变是“有害的”,无论它是否可以避免。

显然,当两个进程并行运行时,总是会不断地更改数据,因此状态的最终结果也可能取决于该竞争。

但是在谈论竞争条件时:当数据的一致性可能被竞争过程破坏时,就会发生有害的竞争条件。

于 2012-08-30T08:19:54.433 回答