The trouble with data - C#. NET

Hello Task

The Trouble with Data
It creates ten Tasks, each of which increments the BankAccount.Balance property 1,000 times. We wait for all of the Tasks to complete and print out the value of Balance. If there are ten Tasks and each of them increments Balance 1,000 times, the final value of Balance should be 10,000 (10 × 1000). Running might produce the following results:

Expected value 10000, Balance: 8840

Press any key to continue . . .

You will certainly get a different result if you run the code. Repeatedly running the program produces a wide range of results. If we are fortunate, we might get the expected result once or twice. In this explains why this happens and how to correct the problem.

Going to the Races
The odd behavior is caused by a data race. Whenever we have two or more Tasks performing operations that update a shared piece data, there is the potential for a race. And if we don’t manage the race properly, we get unexpected and undesirable results. Incrementing the account balance in Listing takes three steps:

  1. Read the current balance from the BankAccount object.
  2. Calculate the new value.
  3. Update the BankAccount with the new balance.

Thinking of this as a three-step process is really a convenience. In fact, we don’t know how the compiler, the runtime, and the operating system are going to perform or optimize our increment operation, but let’s stick with three steps for the sake of simplicity.

We get a range of results with Listing because there are slight variations in the timing of each Task. If you run the program several times, your machine will be in a different state each time: the CPU will be more or less busy; there will be different amounts of memory available, and so on. These differences influence the way in which the Tasks are created, scheduled, and run.

The above shows what can happen when two Tasks race. The Tasks are performing the steps of the balance update slightly out of phase with each other, because they have been started a short time apart.Task 1 reads the current balance and gets 0. A fraction of a second later, Task 2 reads the current balance of the counter and also gets 0—oops. Both Tasks calculate the new balance by incrementing the starting balance they received, so both produce a new balance of 1 —oops, again.

Task 1 stores its new value, and a fraction of a second later, Task 2 comes steaming along and does the same thing. We used two Tasks to perform two increments but got a result of 1. That’s a data race— two Tasks competing to manipulate a piece of shared data without any coordination between them. You can imagine how bad things get in Listing with ten Tasks performing 1,000 increments each.

A simple data race

A simple data race

Creating Some Order
A data race is like a birthday party. The Tasks are the party guests, and when the cake is brought out, the guests can get a little wild. If all of the guests rush to get themselves some cake at the same time, order breaks down. We created a mad scramble to read and write the shared data in Listing and ended up with a data race. The cake in this example is the bank account balance. We have to manage a potential problem whenever multiple Tasks share and update the same data. There are four broad kinds of solution to shared data problems:

  • Sequential execution : We stop parallelizing the work.
  • Immutability : We stop Tasks being able to modify the data.
  • Isolation: We stop sharing the data.
  • Synchronization : We coordinate the actions of the Tasks so that they take turns instead of competing.

We discuss each of these solutions in the following sections and look at the various .NET features available to support them.

All rights reserved © 2020 Wisdom IT Services India Pvt. Ltd Protection Status

C#. NET Topics