Let’s consider having two functions:

increment(x) which increments a value x
retrieve(x) which retrieves a value x

Now let’s have two subjects (processes, threads, users) which use both functions
in order to increment the value and then retrieve it. I will give a real-life example

1. no race condition:

1. A: increment(x) //x=6
2. A: retieve(x) //A.x = 6
3. B: increment(x) //x=7
4. B: retieve(x) //B.x = 7

Let x be 5 before the first operation. After step 2 x holds the value 6 and
A has the correct value. After step 4 x holds the value 7 and B has also the correct
value. However let’s look at another scenario now:

2. race condition:

1. A: increment(x) //x=6
2. B: increment(x) //x=7
3. A: retrieve(x) //A.x=7
4. B: retrieve(x) //B.x=7

Now both subjects have the value 7. This problem is called a race condition as the result
depends on what subject is first and both do not know about the operations of the other.

You might think of that as a very theoretical problem, but it’s not:

Consider the following simple PHP code snippet. Let’s have
a table ‘table’ with the fields id, val1, val2. Let us INSERT a row into db and retrieve
the given id (using MySQL’s ‘auto_increment’ option) afterwards (we might use it for data

  1. mysql_query(“INSERT INTO table (val1, val2) VALUES($val1,$val2)”); //INSERT => autoincrement ID
  2. $result = mysql_query(“SELECT MAX(id) FROM table”); //RETRIEVE ID of row inserted in step 1

You may have identified the possible race condition immediately: What happens if two subjects
(i.e. two users/threads) are using the script at exactly the same time?
You guessed it - if another INSERT happens to be executed right after the first INSERT, the
retrieved id will be wrong for the first subject.

However there is a very easy workaround for this problem (we will have to disable the auto_increment
option here):

    1. $success = false;
    2. while(!$success){
    3. $result = mysql_query(“SELECT MAX(id) FROM table”);
    4. $id = mysql_result($result,0,0);
    5. $id++;
    6. $success = mysql_query(“SELECT MAX(id) FROM table”);
    7. mysql_query(“INSERT INTO table (id, val1, val2) VALUES($id,$val1,$val2)”);
    8. }

      The while-loop is executed until $success will be ‘true’. It is set to ‘true’ whenever the
      INSERT INTO table (id, val1,val2) succedes and it only succedes, when the id, that was ‘guessed’
      by the SELECT MAX(id) query, was not used before (of course considering the id being a unique primary key).
      Please notice, that mysql_result($result,0,0) might return NULL if the table is empty, however this is
      no problem at all as PHP is everything else than a type safe language, so $id=NULL; $id++; leads to $id being 1.

      One might think that these race conditions are less likely to happen. But even if they are unlikely we should
      care about all those eventualities.

      Are you interested in reading more from CodingClues?
      Then subscribe to new postings via RSS or via E-Mail.

      Viewing 5 Comments

      close Reblog this comment
      blog comments powered by Disqus