官术网_书友最值得收藏!

Performing basic atomic operations

This recipe will show you how to perform basic atomic operations on an object to prevent the race condition without blocking threads.

Getting ready

To step through this recipe, you will need Visual Studio 2015. There are no other prerequisites. The source code for this recipe can be found at BookSamples\Chapter2\Recipe1.

How to do it...

To understand basic atomic operations, perform the following steps:

  1. Start Visual Studio 2015. Create a new C# console application project.
  2. In the Program.cs file, add the following using directives:
    using System;
    using System.Threading;
    using static System.Console;
  3. Below the Main method, add the following code snippet:
    static void TestCounter(CounterBase c)
    {
      for (int i = 0; i < 100000; i++)
      {
        c.Increment();
        c.Decrement();
      }
    }
    
    class Counter : CounterBase
    {
      private int _count;
    
      public int Count => _count;
    
      public override void Increment()
      {
        _count++;
      }
    
      public override void Decrement()
      {
        _count--;
      }
    }
    
    class CounterNoLock : CounterBase
    {
      private int _count;
    
      public int Count => _count;
    
      public override void Increment()
      {
        Interlocked.Increment(ref _count);
      }
    
      public override void Decrement()
      {
        Interlocked.Decrement(ref _count);
      }
    }
    
    abstract class CounterBase
    {
      public abstract void Increment();
    
      public abstract void Decrement();
    }
  4. Inside the Main method, add the following code snippet:
    WriteLine("Incorrect counter");
    
    var c = new Counter();
    
    var t1 = new Thread(() => TestCounter(c));
    var t2 = new Thread(() => TestCounter(c));
    var t3 = new Thread(() => TestCounter(c));
    t1.Start();
    t2.Start();
    t3.Start();
    t1.Join();
    t2.Join();
    t3.Join();
    
    WriteLine($"Total count: {c.Count}");
    WriteLine("--------------------------");
    
    WriteLine("Correct counter");
    
    var c1 = new CounterNoLock();
    
    t1 = new Thread(() => TestCounter(c1));
    t2 = new Thread(() => TestCounter(c1));
    t3 = new Thread(() => TestCounter(c1));
    t1.Start();
    t2.Start();
    t3.Start();
    t1.Join();
    t2.Join();
    t3.Join();
    
    WriteLine($"Total count: {c1.Count}");
  5. Run the program.

How it works...

When the program runs, it creates three threads that will execute a code in the TestCounter method. This method runs a sequence of increment/decrement operations on an object. Initially, the Counter object is not thread-safe and we get a race condition here. So, in the first case, a counter value is not deterministic. We could get a zero value; however, if you run the program several times, you will eventually get some incorrect nonzero result.

In Chapter 1, Threading Basics, we resolved this problem by locking our object, causing other threads to be blocked while one thread gets the old counter value and then computes and assigns a new value to the counter. However, if we execute this operation in such a way, it cannot be stopped midway, we would achieve the proper result without any locking, and this is possible with the help of the Interlocked construct. It provides the Increment, Decrement, and Add atomic methods for basic math, and it helps us to write the Counter class without the use of locking.

主站蜘蛛池模板: 基隆市| 河津市| 胶州市| 兴安县| 巩义市| 土默特左旗| 喀喇沁旗| 瓦房店市| 镇安县| 夹江县| 通河县| 来宾市| 武威市| 突泉县| 阿勒泰市| 莲花县| 汤原县| 汝城县| 安国市| 阜康市| 墨竹工卡县| 大连市| 济宁市| 定边县| 故城县| 习水县| 专栏| 宝山区| 广西| 横峰县| 哈尔滨市| 如东县| 怀集县| 五原县| 四子王旗| 东海县| 行唐县| 怀宁县| 新蔡县| 晋中市| 郴州市|