- Mastering C# Concurrency
- Eugene Agafonov Andrew Koryavchenko
- 582字
- 2021-07-09 21:26:07
The System.Threading.Interlocked class
When we reviewed race conditions in the previous chapter, we learned that even a simple increment operation consists of three separate actions. Although modern CPUs can perform such operations at once, it is necessary to make them safe to be used in concurrent programs.
The .NET Framework contains the System.Threading.Interlocked
class that provides access to several operations that are atomic, which means that they are uninterruptible and appear to occur instantaneously to the rest of the system. These are the operations that the lock-free algorithms are based on.
Let's revise a race condition example and compare the locking and Interlocked
class operations. First, we will use the traditional locking approach:
var counterLock = new object(); var counter = 0; ThreadStart proc = () => { for (int i = 0; i < count; i++) { lock (counterLock) counter++; Thread.SpinWait(100); lock (counterLock) counter--; } }; var threads = Enumerable .Range(0, 8) .Select(n => new Thread(proc)) .ToArray(); var sw = Stopwatch.StartNew(); foreach (var thread in threads) thread.Start(); foreach (var thread in threads) thread.Join(); sw.Stop(); Console.WriteLine("Locks: counter={0}, time = {1}ms", counter, sw.ElapsedMilliseconds);
Now, let's replace locking with the Interlocked
class method calls:
counter = 0; ThreadStart proc2 = () => { for (int i = 0; i < count; i++) { Interlocked.Increment(ref counter); Thread.SpinWait(100); Interlocked.Decrement(ref counter); } }; threads = Enumerable .Range(0, 8) .Select(n => new Thread(proc2)) .ToArray(); sw = Stopwatch.StartNew(); foreach (var thread in threads) thread.Start(); foreach (var thread in threads) thread.Join(); sw.Stop(); Console.WriteLine("Lock free: counter={0}, time = {1}ms", counter, sw.ElapsedMilliseconds);
As a result, we got this on a reference computer:
Locks: counter=0, time = 1892ms Locks: counter=0, time = 800ms
Just using atomic operations performed more than twice as well and kept the program logic correct.
Another tricky part is 64-bit integer calculations. When the program runs in the 64-bit mode, the read and write operations for 64-bit integer numbers are atomic. However, when running in the 32-bit mode, these operations become nonatomic and consist of two parts—reading/writing high 32 bits and low 32 bits of the number.
The Interlocked
class contains the Read
method that can read a 64-bit integer in the 32-bit mode as an atomic operation. This is not required in 64-bit mode, but if you compile your program in any CPU mode then you should use this method to guarantee atomicity of reads. There are the Increment
and Decrement
method overloads for 64-bit integers as well, and there is the Add
method that allows us to have atomic addition of 32-bit and 64-bit integers.
Another very important operation is the value exchange. Looking at the following code it is obvious that this operation is not atomic, and thus we must put this code inside some kind of lock to keep this operation correct in a concurrent program:
var tmp = a; a = b; b = tmp;
The Interlocked
class allows us to perform this operation as atomic with the Exchange
method:
b = Interlocked.Exchange(ref a, b)
There are several overloads for this method that allow us to exchange the numeric values of different types including 32-bit and 64-bit integers, the float
and double
values, object references (there is a generic version of this method with the type
parameter), and the IntPtr
structures.
The most complicated atomic operation provided by the Interlocked
class is the CompareExchange
method. It accepts three arguments, then it compares the first argument with the third; if they are equal, it assigns the second argument value to the first argument. This is performed by special instruction on hardware too. We will see an example of this later in this chapter when we try to implement a lock-free queue.
- Visual Basic .NET程序設計(第3版)
- Objective-C Memory Management Essentials
- Apache Spark 2 for Beginners
- 名師講壇:Java微服務架構實戰(SpringBoot+SpringCloud+Docker+RabbitMQ)
- 小學生C++創意編程(視頻教學版)
- Cocos2d-x學習筆記:完全掌握Lua API與游戲項目開發 (未來書庫)
- PySpark Cookbook
- 微服務從小白到專家:Spring Cloud和Kubernetes實戰
- 零基礎學C語言第2版
- 時空數據建模及其應用
- Kotlin極簡教程
- 創意UI:Photoshop玩轉APP設計
- Kotlin Programming By Example
- AMP:Building Accelerated Mobile Pages
- 3D Printing Designs:The Sun Puzzle