What is a race condition?

2018-12-31 00:46发布

When writing multi-threaded applications, one of the most common problems experienced are race conditions.

My questions to the community are:

What is a race condition? How do you detect them? How do you handle them? Finally, how do you prevent them from occurring?

18条回答
浮光初槿花落
2楼-- · 2018-12-31 01:07

Race condition is not only related with software but also related with hardware too. Actually the term was initially coined by the hardware industry.

According to wikipedia:

The term originates with the idea of two signals racing each other to influence the output first.

Race condition in a logic circuit:

enter image description here

Software industry took this term without modification, which makes it a little bit difficult to understand.

You need to do some replacement to map it to the software world:

  • "two signals" => "two threads"/"two processes"
  • "influence the output" => "influence some shared state"

So race condition in software industry means "two threads"/"two processes" racing each other to "influence some shared state", and the final result of the shared state will depend on some subtle timing difference, which could be caused by some specific thread/process launching order, thread/process scheduling, etc.

查看更多
萌妹纸的霸气范
3楼-- · 2018-12-31 01:08

A "race condition" exists when multithreaded (or otherwise parallel) code that would access a shared resource could do so in such a way as to cause unexpected results.

Take this example:

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

If you had 5 threads executing this code at once, the value of x WOULD NOT end up being 50,000,000. It would in fact vary with each run.

This is because, in order for each thread to increment the value of x, they have to do the following: (simplified, obviously)

Retrieve the value of x
Add 1 to this value
Store this value to x

Any thread can be at any step in this process at any time, and they can step on each other when a shared resource is involved. The state of x can be changed by another thread during the time between x is being read and when it is written back.

Let's say a thread retrieves the value of x, but hasn't stored it yet. Another thread can also retrieve the same value of x (because no thread has changed it yet) and then they would both be storing the same value (x+1) back in x!

Example:

Thread 1: reads x, value is 7
Thread 1: add 1 to x, value is now 8
Thread 2: reads x, value is 7
Thread 1: stores 8 in x
Thread 2: adds 1 to x, value is now 8
Thread 2: stores 8 in x

Race conditions can be avoided by employing some sort of locking mechanism before the code that accesses the shared resource:

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

Here, the answer comes out as 50,000,000 every time.

For more on locking, search for: mutex, semaphore, critical section, shared resource.

查看更多
余生请多指教
4楼-- · 2018-12-31 01:11

You can prevent race condition, if you use "Atomic" classes. The reason is just the thread don't separate operation get and set, example is below:

AtomicInteger ai = new AtomicInteger(2);
ai.getAndAdd(5);

As a result, you will have 7 in link "ai". Although you did two actions, but the both operation confirm the same thread and no one other thread will interfere to this, that means no race conditions!

查看更多
高级女魔头
5楼-- · 2018-12-31 01:13

A race condition occurs when two or more threads can access shared data and they try to change it at the same time. Because the thread scheduling algorithm can swap between threads at any time, you don't know the order in which the threads will attempt to access the shared data. Therefore, the result of the change in data is dependent on the thread scheduling algorithm, i.e. both threads are "racing" to access/change the data.

Problems often occur when one thread does a "check-then-act" (e.g. "check" if the value is X, then "act" to do something that depends on the value being X) and another thread does something to the value in between the "check" and the "act". E.g:

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.
}

The point being, y could be 10, or it could be anything, depending on whether another thread changed x in between the check and act. You have no real way of knowing.

In order to prevent race conditions from occurring, you would typically put a lock around the shared data to ensure only one thread can access the data at a time. This would mean something like this:

// 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
查看更多
裙下三千臣
6楼-- · 2018-12-31 01:13

Ok thats 4 questions. one by one answer is as under....

What is a race condition?

It occurs when the output and/or result of the process is critically dependent on the sequence or timing of other events i.e. e.g. 2 signals are racing to change the output first.

How do you detect them?

It leads to error which is difficult to localize.

How do you handle them?

Use Semaphores

And finally,

How do you prevent them from occurring?

One way to avoid race condition is using locking mechanism for resources. but locking resources can lead to deadlocks. which has to be dealt with.

查看更多
人间绝色
7楼-- · 2018-12-31 01:15

A race condition is a kind of bug, that happens only with certain temporal conditions.

Example: Imagine you have two threads, A and B.

In Thread A:

if( object.a != 0 )
    object.avg = total / object.a

In Thread B:

object.a = 0

If thread A is preempted just after having check that object.a is not null, B will do a = 0, and when thread A will gain the processor, it will do a "divide by zero".

This bug only happen when thread A is preempted just after the if statement, it's very rare, but it can happen.

查看更多
登录 后发表回答