.NET C# 單執行緒 同步 多執行緒 非同步 執行緒同步 Synchronization 邏輯處理器數量 設計探討 : Part 3 在多執行緒下,使用 lock 關鍵字來做到執行緒安全
- .NET C# 單執行緒 同步 多執行緒 非同步 執行緒同步 Synchronization 邏輯處理器數量 設計探討 : Part 1 在單一執行緒下,同步執行加一與減一方法
- .NET C# 單執行緒 同步 多執行緒 非同步 執行緒同步 Synchronization 邏輯處理器數量 設計探討 : Part 2 在多執行緒下,非同步執行加一與減一方法,造成執行緒不安全的現象
- .NET C# 單執行緒 同步 多執行緒 非同步 執行緒同步 Synchronization 邏輯處理器數量 設計探討 : Part 3 在多執行緒下,使用 lock 關鍵字來做到執行緒安全
- .NET C# 單執行緒 同步 多執行緒 非同步 執行緒同步 Synchronization 邏輯處理器數量 設計探討 : Part 4 在多執行緒下,使用 Interlocked 來做到執行緒安全
- .NET C# 單執行緒 同步 多執行緒 非同步 執行緒同步 Synchronization 邏輯處理器數量 設計探討 : Part 5 在多執行緒下,不要全部都使用執行緒同步機制 來做到執行緒安全
在這篇文章中,將會使用 C# lock 關鍵字,把需要存取共用變數的關鍵區域 Critical Section 程式碼進行鎖定,讓這個多執行緒的程式具有執行緒安全的特性。
在這篇文章所提到的專案原始碼,可以從 GitHub 下載
進行多執行緒的測試,使用 lock 關鍵字
為了要設計出執行緒安全的程式碼,對於要對共用靜態變數
AddSub.counter
進行加一與減一計算的時候,將使用 lock 關鍵字將其包裝起來,如同底下程式碼class AddSub
{
public static int counter = 0;
public static object locker = new object();
public void Adds(AddSubAction addSubAction = AddSubAction.NoLock)
{
for (int i = 0; i < int.MaxValue; i++)
{
lock (locker)
{
counter++;
}
}
}
public void Subs(AddSubAction addSubAction = AddSubAction.NoLock)
{
for (int i = 0; i < int.MaxValue; i++)
{
lock (locker)
{
counter--;
}
}
}
}
經過這樣的修正,當執行緒執行到
counter++
或者 counter--
程式碼的時候,將會有 lock 進行鎖定保護,也就是說,這裡使用的 核心模式 Kernel Mode 的同步建構子 Synchronization Constructor 來進行鎖定,透過 lock 關鍵字,可以確保同一個時間,對於 lock 內的程式碼僅會有一個執行緒可以執行 lock 內的程式碼。
對於使用 lock 關鍵字的時候,需要提供一個物件,這裡將會宣告一個靜態變數
public static object locker = new object();
底下將會使用 C# lock 關鍵字,並請指定不同邏輯處理器數量下的執行結果。
ThreadSynchronization yes UsingNETLock 10000000
Counter=0, 88,960ms
ThreadSynchronization yes UsingNETLock 10100000
Counter=0, 181,327ms
ThreadSynchronization yes UsingNETLock 10101000
Counter=0, 133,869ms
ThreadSynchronization yes UsingNETLock 11000000
Counter=0, 106,076ms
ThreadSynchronization yes UsingNETLock 11100000
Counter=0, 107,196ms
ThreadSynchronization yes UsingNETLock 11110000
Counter=0, 113,402ms
ThreadSynchronization yes UsingNETLock 11111111
Counter=0, 121,130ms
從上面的執行結果可以看到,不論指定的邏輯處理器數量是多少,當多執行緒程式執行完畢之後,這個程式的執行結果是正確的;不過,執行這個多執行緒程式所花費的時間真的慘不忍睹,最好的執行時間竟然是僅使用一顆 CPU 的
10000000
的執行結果,需要花費 89 秒的時間,這比起同步程式執行所花費的時間 7.5 秒左右,真的高出太多了,而且,當使用全部八顆邏輯處理器的時候,整體執行完成的時間卻需要高達 121 秒。
總之,現在已經設計出一個具有執行緒安全的程式碼了,接下來要來嘗試解決執行速度過慢的問題。
AddSub.counter
這個共用靜態變數於最後執行結果必須為0。