The pedagogical bank account example

A classic (pedagogical) example is that of the faulty bank account software application. Imagine that Kaloor (needless to say, fictional names and figures have been employed here), a freelance sculptor, has an account with his bank; his current balance is $12,000.00. Two transactions, deposits of $3,000 and $8,000, which are payments for work he has successfully completed, are issued simultaneously. It does not take a genius to see that (assuming that there are no other transactions), very soon, his account balance should reflect an amount of $23,000.00.

For the purpose of this example, let's visualize that the banking software application is a multithreaded process; to keep things very simple, we consider that a thread is spawned off to handle a transaction. The server system that the software runs upon is a powerful multicore machineit has, say, 12 CPU cores. This, of course, implies that threads can run in parallel on different cores simultaneously.

So, let's visualize that for each of Kaloor's transactions we have a thread running to perform it—thread A and thread B. Thread A (running on, say, CPU #0) works upon the first deposit of $3,000 and thread B (running on, say, CPU #1) works upon the (almost immediate) second deposit of $8,000.

We consider two cases here:

  • The case where, by chance, the transactions go through successfully. The following diagram clearly shows this case:

Figure 1: The bank account; correct, by chance
  • The case where, again by chance, the transactions do not go through successfully. The following diagram shows this case:

Figure 2: The bank account; incorrect, by chance

The problem area is highlighted in the preceding tables: It's quite clear that thread B has performed an invalid read on the balance—it has read a stale value of $12,000 (the value as of time t4) instead of fetching the actual current value of $15,000—resulting in an effective loss of $3,000 for poor Kaloor.

How did this happen? In a nutshell, a race condition has caused the problem. To understand the race, look carefully at the preceding table and visualize the activity:

  • The variable representing the current balance in the account; balance is global:
    • It is residing in the data segment
    • It is shared by all threads of the process
  • At time t3, thread A on CPU #0: A deposit of $3,000 is made; the balance is still $12,000 (not updated yet)
  • At time t4, thread B on CPU #1: A deposit of $8,000 is made; the balance is still $12,000 (not updated yet)
  • At time t5:
    • Thread A on CPU #0: update the balance
    • Simultaneously, but on the other core:
      • Thread B on CPU #1: update the balance
      • By chance, what if thread B ran on CPU #1 a few microseconds before thread A on CPU #0 could update the balance variable!?
      • Then, thread B reads the balance as $12,000 ($3,000 short!) This is called a dirty read and is at the heart of the problem. This very situation is called a race; a race being a situation in which the outcome is undefined and unpredictable. In most cases, this will be a problem (as it is here); in some rare cases where it does not matter, it's referred to as a benign race. 

The fact to be emphasized is that the operation of depositing funds and updating the balance (or the converse, withdrawing funds and updating the balance) has to be guaranteed to be atomic. They cannot race, as that would be a defect (a bug).

The phrase atomic operation (or atomicity) in a software programming context implies that the operation, once begun, will run to completion without interruption.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset