博客 / 詳情

返回

深入理解 C#.NET Interlocked.Increment:原子操作的核心

簡介

Interlocked.Increment.NET 中一個重要的線程安全操作方法,用於以原子方式遞增變量的值。它位於 System.Threading 命名空間中,提供了一種輕量級的線程同步機制。

這些方法包括:

方法 作用
Increment(ref int location) 原子 +1
Decrement(ref int location) 原子 -1
Add(ref int location, int value) 原子加指定值
Exchange(ref T location, T value) 原子交換值
CompareExchange(ref T location, T value, T comparand) CAS 操作(Compare-And-Swap)
Read(ref long location) 原子讀取 long 值

這些操作都是 線程安全且無鎖 (lock-free) 的。

核心概念與作用

原子操作定義

  • 不可分割性:操作要麼完全執行,要麼完全不執行
  • 線程安全:多線程環境下保證操作完整性
  • 無鎖機制:避免傳統鎖帶來的性能開銷

核心特性

特性 説明
線程安全 無需額外同步機制
硬件級原子性 使用 CPU 原子指令實現
內存屏障 確保操作前後內存一致性
高性能 比鎖機制快 10-50 倍

底層實現原理

x86/x64 架構實現

; x86 實現
lock xadd [location], eax

; x64 實現
lock xadd [location], rax
  • lock 前綴:鎖定內存總線,確保操作原子性
  • xadd 指令:交換並相加寄存器與內存值

基本用法

using System;
using System.Threading;

class Program
{
    private static int _counter = 0;

    static void Main()
    {
        var threads = new Thread[10];

        for (int i = 0; i < 10; i++)
        {
            threads[i] = new Thread(IncrementCounter);
            threads[i].Start();
        }

        foreach (var t in threads)
            t.Join();

        Console.WriteLine($"最終計數值: {_counter}");
    }

    static void IncrementCounter()
    {
        for (int i = 0; i < 1000; i++)
        {
            Interlocked.Increment(ref _counter);
        }
    }
}

輸出:

最終計數值: 10000

即使多個線程併發操作同一個變量,也不會出現競爭問題。

為什麼不能直接用 _counter++

_counter++ 實際上是三步操作:

int temp = _counter;
temp = temp + 1;
_counter = temp;

在多線程環境中,這三步可能被打斷,比如:

線程A 線程B
讀取 _counter = 0 讀取 _counter = 0
+1 → 1 +1 → 1
寫回 _counter = 1 寫回 _counter = 1

最終 _counter = 1,而不是 2。
這就是競爭條件(race condition)。

Interlocked.Increment 內部使用 CPU 的原子指令(如 x86LOCK INC),
確保操作不可中斷,因此絕對線程安全。

返回值

Interlocked.Increment 會返回自增後的值:

int count = 0;
int newValue = Interlocked.Increment(ref count);

Console.WriteLine(newValue); // 1
Console.WriteLine(count);    // 1

所以它可以直接用於生成唯一 ID、計數等邏輯。

支持的類型

方法 支持的類型
Interlocked.Increment int, long
Interlocked.Decrement int, long
Interlocked.Add int, long
Interlocked.Exchange int, long, float, double, object
Interlocked.CompareExchange 同上

性能分析

相比於使用 lock 的同步方式:

lock(_lockObj)
{
    _counter++;
}

Interlocked.Increment

✅ 無鎖操作(Lock-free
✅ 內核級原子性(基於 CPU 指令)
✅ 極高性能(納秒級)

實測在多線程計數場景中性能提升 5~10 倍以上。
非常適合高頻次計數(如統計請求量、日誌寫入次數、對象實例數)。

完整的原子操作方法集

using System;
using System.Threading;

class InterlockedCompleteExample
{
    private static int _counter = 0;
    private static long _bigCounter = 0;
    private static int _value = 10;
    private static object _syncObject = new object();

    static void DemonstrateAllMethods()
    {
        // 1. Increment - 遞增
        int result1 = Interlocked.Increment(ref _counter);
        Console.WriteLine($"After Increment: {_counter}, Returned: {result1}");

        // 2. Decrement - 遞減
        int result2 = Interlocked.Decrement(ref _counter);
        Console.WriteLine($"After Decrement: {_counter}, Returned: {result2}");

        // 3. Add - 加法
        int result3 = Interlocked.Add(ref _counter, 5);
        Console.WriteLine($"After Add(5): {_counter}, Returned: {result3}");

        // 4. Exchange - 交換
        int original = Interlocked.Exchange(ref _value, 20);
        Console.WriteLine($"After Exchange: {_value}, Original: {original}");

        // 5. CompareExchange - 比較並交換
        int comparand = 20;
        int newValue = 30;
        int result5 = Interlocked.CompareExchange(ref _value, newValue, comparand);
        Console.WriteLine($"After CompareExchange: {_value}, Returned: {result5}");

        // 6. Read - 讀取 long 類型(確保在32位系統上原子讀取)
        long readResult = Interlocked.Read(ref _bigCounter);
        Console.WriteLine($"Read long value: {readResult}");

        // 7. And - 位與操作(.NET 5+)
        // Interlocked.And(ref _value, 0x0F);

        // 8. Or - 位或操作(.NET 5+)
        // Interlocked.Or(ref _value, 0xF0);
    }
}

典型應用場景

多線程計數器

private static int _activeConnections;

public static void OnClientConnect()
{
    var current = Interlocked.Increment(ref _activeConnections);
    Console.WriteLine($"連接數增加到 {current}");
}

public static void OnClientDisconnect()
{
    var current = Interlocked.Decrement(ref _activeConnections);
    Console.WriteLine($"連接數減少到 {current}");
}

分配唯一自增 ID

private static int _nextId = 0;

public static int GetNextId()
{
    return Interlocked.Increment(ref _nextId);
}

控制併發訪問次數

private static int _running = 0;

public async Task ProcessAsync()
{
    if (Interlocked.Increment(ref _running) > 5)
    {
        Console.WriteLine("超過併發限制,拒絕執行");
        Interlocked.Decrement(ref _running);
        return;
    }

    try
    {
        await DoWorkAsync();
    }
    finally
    {
        Interlocked.Decrement(ref _running);
    }
}

高級用法

無鎖棧實現

public class LockFreeStack<T>
{
    private class Node
    {
        public T Value { get; }
        public Node Next { get; set; }

        public Node(T value)
        {
            Value = value;
        }
    }

    private Node _head;

    public void Push(T value)
    {
        var newNode = new Node(value);
        Node oldHead;
        do
        {
            oldHead = _head;
            newNode.Next = oldHead;
        }
        while (Interlocked.CompareExchange(ref _head, newNode, oldHead) != oldHead);
    }

    public bool TryPop(out T value)
    {
        Node oldHead;
        do
        {
            oldHead = _head;
            if (oldHead == null)
            {
                value = default;
                return false;
            }
        }
        while (Interlocked.CompareExchange(ref _head, oldHead.Next, oldHead) != oldHead);

        value = oldHead.Value;
        return true;
    }

    public bool IsEmpty => _head == null;
}

線程安全的對象池

public class ObjectPool<T> where T : class, new()
{
    private class Node
    {
        public T Value { get; }
        public Node Next { get; set; }

        public Node(T value)
        {
            Value = value;
        }
    }

    private Node _head;
    private int _count = 0;
    private readonly int _maxSize;

    public ObjectPool(int maxSize = 100)
    {
        _maxSize = maxSize;
    }

    public void Return(T item)
    {
        if (Interlocked.Read(ref _count) >= _maxSize)
        {
            return; // 池已滿,丟棄對象
        }

        var newNode = new Node(item);
        Node oldHead;
        do
        {
            oldHead = _head;
            newNode.Next = oldHead;
        }
        while (Interlocked.CompareExchange(ref _head, newNode, oldHead) != oldHead);

        Interlocked.Increment(ref _count);
    }

    public T Get()
    {
        Node oldHead;
        do
        {
            oldHead = _head;
            if (oldHead == null)
            {
                Interlocked.Increment(ref _count);
                return new T();
            }
        }
        while (Interlocked.CompareExchange(ref _head, oldHead.Next, oldHead) != oldHead);

        Interlocked.Decrement(ref _count);
        return oldHead.Value;
    }

    public int Count => (int)Interlocked.Read(ref _count);
}

與 lock、Monitor 的區別

特性 Interlocked lock / Monitor
是否鎖住線程
原子性
是否可中斷 不可 可被其他線程等待
性能 極高 一般
適用場景 簡單數值、指針操作 多步複雜邏輯
  • 如果只是“計數/標誌位更新”,用 Interlocked
  • 如果涉及多個變量或邏輯組合,用 lock

CompareExchange (CAS) 補充理解

Interlocked.CompareExchange 是構建更復雜無鎖結構的核心:

int location = 0;
int newValue = 1;
int expected = 0;

int old = Interlocked.CompareExchange(ref location, newValue, expected);
  • 如果 location == expected → 把 location 改成 newValue
  • 否則什麼都不做;
  • 返回修改前的舊值。

這就是經典的 Compare-And-Swap (CAS),
是無鎖隊列、無鎖堆棧、無鎖緩存等的基礎原語。

與 async/await 的結合注意事項

Interlocked 是同步原子操作,適用於多線程併發,不涉及異步上下文。
即使在 async 方法中使用,也完全沒問題:

private static int _count;

public async Task LogAsync()
{
    Interlocked.Increment(ref _count);
    await File.AppendAllTextAsync("log.txt", $"{_count}\n");
}
  • 它不會保證異步順序;
  • 它保證計數線程安全。

總結

特性 Interlocked.Increment
命名空間 System.Threading
返回值 自增後的值
線程安全 ✅ 原子操作
鎖機制 無鎖
支持類型 int, long
性能 極高
應用場景 計數、ID生成、併發控制、原子狀態更新
替代方案 lock、Monitor、Volatile、CAS
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.