首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

.NET 並行程式設計系列(七):共享資料競爭問題與四大解決策略

     編輯:關於.NET

並行程式設計核心挑戰在於共享資料競爭。本文以銀行帳戶餘額並行增減為例,剖析競爭成因並提出四大解決方向。

競爭問題重現

10 個 Task 各自將 Balance 遞增 1000 次,預期結果 10000,實際每次執行結果皆不同且小於 10000:

class BankAccount { public int Balance { get; set; } }
var account = new BankAccount();
Task[] tasks = new Task[10];
for (int i = 0; i < 10; i++) {
    tasks[i] = Task.Factory.StartNew(() => {
        for (int j = 0; j < 1000; j++) account.Balance++;
    });
}
Task.WaitAll(tasks);
Console.WriteLine($"Expected: 10000, Actual: {account.Balance}");

競爭成因分析

account.Balance++ 非原子操作,包含三步驟:

  1. 讀取目前值
  2. 計算新值(建立暫存變數 +1)
  3. 寫回新值

兩個 Task 交錯執行時:

Task1 讀取 0 → Task2 讀取 0 → Task1 寫入 1 → Task2 寫入 1
// 兩次遞增,結果卻只增加 1

因作業系統排程不確定性,每次執行交錯順序不同,導致結果隨機。

四大解決策略

策略核心思想比喻(分蛋糕)
1. 循序執行一次只允許一個 Task 存取共享資料一次只讓一個人拿蛋糕
2. 資料不可變共享資料唯讀,不可修改蛋糕只能看不能吃
3. 隔離每個 Task 擁有資料私有複本每人分一塊自己的蛋糕
4. 同步協調 Task 存取順序(鎖、訊號等)排隊依序拿蛋糕

策略一:循序執行

本質退化為單執行緒,放棄平行優勢,僅適合極簡單場景。

策略二:資料不可變

C# 關鍵字 const(編譯期常數,型別存取)與 readonly(執行期唯讀,建構函式可指派):

public class ImmutableBankAccount {
    public const int AccountNumber = 123456;
    public readonly int Balance;
    public ImmutableBankAccount(int initial) { Balance = initial; }
}

適用於真正不可變的資料結構,限制較大,非通用方案。

後續文章將詳細介紹

  • 隔離策略:ThreadLocal<T>、區域狀態、資料分割
  • 同步策略:lock、Monitor、Interlocked、Semaphore、ReaderWriterLockSlim 等
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved