本文主要是試驗在順序進入等待 SemaphoreSlim 的任務是否會按照順序經過鎖執行 ...
本文主要是試驗在順序進入等待 SemaphoreSlim 的任務是否會按照順序經過鎖執行
我在一個有趣的WPF程式裡面,需要限制任務同時執行的線程數量,不然用戶就會說用我的程式會讓電腦卡渣。而我的任務是需要按照指定順序執行的,我需要每次同時僅執行10個任務,同時任務執行按照傳入的順序
此時可以用到 SemaphoreSlim 這個類,這個類的作用如下,給定初始的可以通過鎖的數量,以及這個最大可以通過鎖的數量。通過 Wait 方法進行等待,如果當前已經有超過可以通過的任務通過了,那麼在 Wait 方法將會阻塞。如果沒有超過可以通過的數量,那麼將可以通過
使用 Release 方法可以添加一個或多個可以通過的數量,但是可以通過的數量最大不會超過初始化時傳入的最大可以通過鎖的數量的值
如下麵代碼
var semaphoreSlim = new SemaphoreSlim(10, 20);
此時表示初始化的時候,可以讓 10 個任務通過鎖,也就是初始化的時候可以有10次調用 Wait 方法能通過
而第二個參數表示最大的可以通過的數量,通過 Release 可以添加一個或多個可以通過鎖的任務,如 semaphoreSlim.Release(100);
表示設置有 100 個可以通過鎖的任務,但是實際上在上面代碼裡面,因為設置了最大值是 20 也就是即使寫 100 其實之後能通過的任務只有 20 個
而本文的測試在於我有任務按照順序調用 Wait 方法進入等待,如我的任務有序號,我按照任務1 任務2 任務3 的順序調用Wait方法,同時此時的鎖的可以通過的數量是 0 也就是所有任務在等待
之後我通過 Release 方法的不斷調用,請問此時通過鎖的任務是否和隊列一樣,先等待的任務就先通過鎖。答案是這樣的
先調用 Wait 方法的任務,在鎖開始釋放的時候就先通過,我通過一個有趣的代碼用來測試
我需要有很多線程進入鎖的 Wait 方法,但是這些線程每個線程是一個任務,這些任務有順序,進入等待方法的時候按照順序進入
而小伙伴都知道,創建線程的先後順序不會等於線程執行的先後順序,所以我使用了 AutoResetEvent 線上程創建然後執行開始之後再創建下一個線程
先通過 SemaphoreSlim 創建一個初始值是 10 而最大值是 10 的鎖,然後創建一個 AutoResetEvent 設置預設能通過一次
var semaphoreSlim = new SemaphoreSlim(10, 10);
private static readonly AutoResetEvent _autoResetEvent = new AutoResetEvent(true);
接下來進入迴圈創建線程,創建線程的時候先等待 AutoResetEvent 鎖,而線上程執行的時候釋放 AutoResetEvent 鎖,這樣就能讓線程一定是在上一個線程執行之後再創建。而設置 AutoResetEvent 的初始值是通過,也就是第一個線程可以創建,但第二個線程需要等待第一個線程開始執行再創建
for (int i = 0; i < 1000; i++)
{
var n = i;
_autoResetEvent.WaitOne();
new Thread(() => { GeregelkunoNeawhikarcee(semaphoreSlim, n); }).Start();
}
添加 GeregelkunoNeawhikarcee 方法,在方法進入的時候,也就是線程開始執行,釋放 AutoResetEvent 鎖,這樣就能讓下一個線程創建
_autoResetEvent.Set();
進入等待 SemaphoreSlim 此時等待是按照線程創建的順序等待
semaphoreSlim.Wait();
接下來輸出當前的任務號,主要用來調試是否通過鎖的順序和線程進入等待的順序相同
Console.WriteLine(n);
接下來通過 Thread.Sleep 模擬執行長任務
在任務執行完成之後釋放鎖讓下一個任務開始,全部代碼放在這裡
static void Main(string[] args)
{
var semaphoreSlim = new SemaphoreSlim(10, 10);
for (int i = 0; i < 1000; i++)
{
var n = i;
_autoResetEvent.WaitOne();
new Thread(() => { GeregelkunoNeawhikarcee(semaphoreSlim, n); }).Start();
}
Console.Read();
}
private static readonly AutoResetEvent _autoResetEvent = new AutoResetEvent(true);
private static void GeregelkunoNeawhikarcee(SemaphoreSlim semaphoreSlim, int n)
{
Console.WriteLine($"{n} 進入");
_autoResetEvent.Set();
semaphoreSlim.Wait();
Console.WriteLine(n);
Thread.Sleep(TimeSpan.FromSeconds(1));
semaphoreSlim.Release();
}
可以看到代碼是按照順序輸出的
本文代碼放在github歡迎小伙伴訪問
本作品採用知識共用署名-非商業性使用-相同方式共用 4.0 國際許可協議進行許可。歡迎轉載、使用、重新發佈,但務必保留文章署名林德熙(包含鏈接:http://blog.csdn.net/lindexi_gd ),不得用於商業目的,基於本文修改後的作品務必以相同的許可發佈。如有任何疑問,請與我聯繫。