什么是竞态条件?

17 浏览
0 Comments

什么是竞态条件?

在编写多线程应用程序时,最常遇到的问题之一是竞态条件。

我向社区提出的问题是:

  • 什么是竞态条件?
  • 如何检测它们?
  • 如何处理它们?
  • 最后,如何防止它们发生?
admin 更改状态以发布 2023年5月22日
0
0 Comments

“竞争条件”指的是多线程(或其他并行)代码访问共享资源时,以一种可能导致意外结果的方式进行访问。以以下示例为例:

for ( int i = 0; i < 10000000; i++ )
{
   x = x + 1; 
}

如果您同时有5个线程执行此代码,则x的值不会最终为50000000,实际上会因每次运行而异。这是因为,为了使每个线程增加x的值,它们必须执行以下操作:(显然是简化版) 1.检索x的值。 2. 将1添加到此值。 3. 将此值存储到x. 在涉及共享资源时,任何线程都可以在此过程的任何时候处于任何步骤,它们可以互相干扰。X的状态可以在读取x和将其写回时的时间段内由另一个线程更改。 假设一个线程检索了x的值,但还没有将其存储。另一个线程也可以检索x的相同值(因为还没有线程更改它),然后他们将同时将相同值(x+1)存储回x! 例如: 线程1:读取x,值为7 线程1:将1添加到x,值现在为8 线程2:读取x,值为7 线程1:在x中存储8 线程2:将1添加到x,值现在为8 线程2:在x中存储8 可以通过在访问共享资源的代码之前采用某种锁定机制来避免竞争条件:

for ( int i = 0; i < 10000000; i++ )
{
   //lock x
   x = x + 1; 
   //unlock x
}

在这里,答案每次都是50000000。 有关锁定的更多信息,请搜索:mutex、semaphore、critical section、shared resource。

0
0 Comments

当两个或多个线程可以访问共享数据并尝试同时更改它时,就会发生竞态条件。因为线程调度算法可以在任何时候在线程之间交换,所以您不知道线程尝试访问共享数据的顺序。因此,数据更改的结果取决于线程调度算法,即两个线程正在“竞赛”以访问/更改数据。\n\n在一个线程执行“检查-然后-执行”操作(例如,“检查”值是否为X,然后“执行”依赖于X值的操作),而另一个线程在“检查”和“执行”之间对该值进行操作时,通常会出现问题。例如:\n

if (x == 5) // The "Check"
{
   y = x * 2; // The "Act"
   // If another thread changed x in between "if (x == 5)" and "y = x * 2" above,
   // y will not be equal to 10.
}

\n重点是,y可以是10,也可以是任何其他值,取决于另一个线程是否在检查和执行之间更改了x。您真正没有方法知道。\n\n为了防止竞态条件发生,通常会在共享数据周围放置一个锁,以确保只有一个线程可以同时访问数据。这意味着以下内容: \n

// Obtain lock for x
if (x == 5)
{
   y = x * 2; // Now, nothing can change x until the lock is released. 
              // Therefore y = 10
}
// release lock for x

0