<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
兩者都可以限制同時存取某一資源或資源池的執行緒數。
這裡先不扯理論,我們從案例入手,通過範例程式碼,慢慢深入瞭解。
這裡,先列出 Semaphore 類常用的 API。
其建構函式如下:
建構函式 | 說明 |
---|---|
Semaphore(Int32, Int32) | 初始化 Semaphore 類的新範例,並指定初始入口數和最大並行入口數。 |
Semaphore(Int32, Int32, String) | 初始化 Semaphore 類的新範例,並指定初始入口數和最大並行入口數,根據需要指定系統訊號燈物件的名稱。 |
Semaphore(Int32, Int32, String, Boolean) | 初始化 Semaphore 類的新範例,並指定初始入口數和最大並行入口數,還可以選擇指定系統號誌物件的名稱,以及指定一個變數來接收指示是否建立了新系統號誌的值。 |
Semaphore 使用純粹的核心時間(kernel-time)方式(等待時間很短),並且支援在不同的程序間同步執行緒(像Mutex)。
Semaphore 常用方法如下:
方法 | 說明 |
---|---|
Close() | 釋放由當前 WaitHandle佔用的所有資源。 |
OpenExisting(String) | 開啟指定名稱為號誌(如果已經存在)。 |
Release() | 退出號誌並返回前一個計數。 |
Release(Int32) | 以指定的次數退出號誌並返回前一個計數。 |
TryOpenExisting(String, Semaphore) | 開啟指定名稱為號誌(如果已經存在),並返回指示操作是否成功的值。 |
WaitOne() | 阻止當前執行緒,直到當前 WaitHandle 收到訊號。 |
WaitOne(Int32) | 阻止當前執行緒,直到當前 WaitHandle 收到訊號,同時使用 32 位帶符號整數指定時間間隔(以毫秒為單位)。 |
WaitOne(Int32, Boolean) | 阻止當前執行緒,直到當前的 WaitHandle 收到訊號為止,同時使用 32 位帶符號整數指定時間間隔,並指定是否在等待之前退出同步域。 |
WaitOne(TimeSpan) | 阻止當前執行緒,直到當前範例收到訊號,同時使用 TimeSpan 指定時間間隔。 |
WaitOne(TimeSpan, Boolean) | 阻止當前執行緒,直到當前範例收到訊號為止,同時使用 TimeSpan 指定時間間隔,並指定是否在等待之前退出同步域。 |
我們來直接寫程式碼,這裡使用 《原子操作 Interlocked》 中的範例,現在我們要求,採用多個執行緒執行計算,但是隻允許最多三個執行緒同時執行執行。
使用 Semaphore ,有四個個步驟:
new 範例化 Semaphore,並設定最大執行緒數、初始化時可進入執行緒數;
使用 .WaitOne();
獲取進入許可權(在獲得進入許可權前,執行緒處於阻塞狀態)。
離開時使用 Release()
釋放佔用。
Close()
釋放Semaphore 物件。
《原子操作 Interlocked》 中的範例改進如下:
class Program { // 求和 private static int sum = 0; private static Semaphore _pool; // 判斷十個執行緒是否結束了。 private static int isComplete = 0; // 第一個程式 static void Main(string[] args) { Console.WriteLine("執行程式"); // 設定允許最大三個執行緒進入資源池 // 一開始設定為0,就是初始化時允許幾個執行緒進入 // 這裡設定為0,後面按下按鍵時,可以放通三個執行緒 _pool = new Semaphore(0, 3); for (int i = 0; i < 10; i++) { Thread thread = new Thread(new ParameterizedThreadStart(AddOne)); thread.Start(i + 1); } Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("任意按下鍵(不要按關機鍵),可以開啟資源池"); Console.ForegroundColor = ConsoleColor.White; Console.ReadKey(); // 准許三個執行緒進入 _pool.Release(3); // 這裡沒有任何意義,就單純為了演示檢視結果。 // 等待所有執行緒完成任務 while (true) { if (isComplete >= 10) break; Thread.Sleep(TimeSpan.FromSeconds(1)); } Console.WriteLine("sum = " + sum); // 釋放池 _pool.Close(); } public static void AddOne(object n) { Console.WriteLine($" 執行緒{(int)n}啟動,進入佇列"); // 進入佇列等待 _pool.WaitOne(); Console.WriteLine($"第{(int)n}個執行緒進入資源池"); // 進入資源池 for (int i = 0; i < 10; i++) { Interlocked.Add(ref sum, 1); Thread.Sleep(TimeSpan.FromMilliseconds(500)); } // 解除佔用的資源池 _pool.Release(); isComplete += 1; Console.WriteLine($" 第{(int)n}個執行緒退出資源池"); } }
看著程式碼有點多,快去執行一下,看看結果。
範例化 Semaphore 使用了new Semaphore(0,3);
,其建構函式原型為
public Semaphore(int initialCount, int maximumCount);
initialCount 表示一開始允許幾個程序進入資源池,如果設定為0,所有執行緒都不能進入,要一直等資源池放通。
maximumCount 表示最大允許幾個執行緒進入資源池。
Release()
表示退出號誌並返回前一個計數。這個計數指的是資源池還可以進入多少個執行緒。
可以看一下下面的範例:
private static Semaphore _pool; static void Main(string[] args) { _pool = new Semaphore(0, 5); _pool.Release(5); new Thread(AddOne).Start(); Thread.Sleep(TimeSpan.FromSeconds(10)); _pool.Close(); } public static void AddOne() { _pool.WaitOne(); Thread.Sleep(1000); int count = _pool.Release(); Console.WriteLine("在此執行緒退出資源池前,資源池還有多少執行緒可以進入?" + count); }
前面我們學習到 Mutex,這個類是全域性作業系統起作用的。我們從 Mutex 和 Semphore 中,也看到了 號誌這個東西。
號誌分為兩種型別:本地號誌和命名系統號誌。
當 name 為 null 或者為空時,Mutex 的號誌時區域性號誌,否則 Mutex 的號誌是命名系統號誌。
Semaphore 的話,也是兩種情況都有。
如果使用接受名稱的建構函式建立 Semaphor 物件,則該物件將與該名稱的作業系統號誌關聯。
兩個建構函式:
Semaphore(Int32, Int32, String) Semaphore(Int32, Int32, String, Boolean)
上面的建構函式可以建立多個表示同一命名系統號誌的 Semaphore 物件,並可以使用 OpenExisting 方法開啟現有的已命名系統號誌。
我們上面使用的範例就是區域性號誌,程序中參照本地 Semaphore 物件的所有執行緒都可以使用。 每個 Semaphore 物件都是單獨的本地號誌。
SemaphoreSlim 跟 Semaphore 有啥關係?
微軟檔案:
SemaphoreSlim 表示對可同時存取資源或資源池的執行緒數加以限制的 Semaphore 的輕量替代。
SemaphoreSlim 不使用號誌,不支援程序間同步,只能在程序內使用。
它有兩個建構函式:
建構函式 | 說明 |
---|---|
SemaphoreSlim(Int32) | 初始化 SemaphoreSlim 類的新範例,以指定可同時授予的請求的初始數量。 |
SemaphoreSlim(Int32, Int32) | 初始化 SemaphoreSlim 類的新範例,同時指定可同時授予的請求的初始數量和最大數量。 |
我們改造一下前面 Semaphore 中的範例:
class Program { // 求和 private static int sum = 0; private static SemaphoreSlim _pool; // 判斷十個執行緒是否結束了。 private static int isComplete = 0; static void Main(string[] args) { Console.WriteLine("執行程式"); // 設定允許最大三個執行緒進入資源池 // 一開始設定為0,就是初始化時允許幾個執行緒進入 // 這裡設定為0,後面按下按鍵時,可以放通三個執行緒 _pool = new SemaphoreSlim(0, 3); for (int i = 0; i < 10; i++) { Thread thread = new Thread(new ParameterizedThreadStart(AddOne)); thread.Start(i + 1); } Console.WriteLine("任意按下鍵(不要按關機鍵),可以開啟資源池"); Console.ReadKey(); // _pool.Release(3); // 這裡沒有任何意義,就單純為了演示檢視結果。 // 等待所有執行緒完成任務 while (true) { if (isComplete >= 10) break; Thread.Sleep(TimeSpan.FromSeconds(1)); } Console.WriteLine("sum = " + sum); // 釋放池 } public static void AddOne(object n) { Console.WriteLine($" 執行緒{(int)n}啟動,進入佇列"); // 進入佇列等待 _pool.Wait(); Console.WriteLine($"第{(int)n}個執行緒進入資源池"); // 進入資源池 for (int i = 0; i < 10; i++) { Interlocked.Add(ref sum, 1); Thread.Sleep(TimeSpan.FromMilliseconds(200)); } // 解除佔用的資源池 _pool.Release(); isComplete += 1; Console.WriteLine($" 第{(int)n}個執行緒退出資源池"); } }
SemaphoreSlim 不需要 Close()
。
兩者在程式碼上的區別是就這麼簡單。
如果使用下面的建構函式範例化 Semaphor(引數name不能為空),那麼建立的物件在整個作業系統內都有效。
public Semaphore (int initialCount, int maximumCount, string name);
Semaphorslim 則只在程序內內有效。
SemaphoreSlim 類不會對 Wait
、WaitAsync
和 Release
方法的呼叫強制執行執行緒或任務標識。
而 Semaphor 類,會對此進行嚴格監控,如果對應呼叫數量不一致,會出現異常。
此外,如果使用 SemaphoreSlim(Int32 maximumCount) 建構函式來範例化 SemaphoreSlim 物件,獲取其 CurrentCount 屬性,其值可能會大於 maximumCount。 程式設計人員應負責確保呼叫一個 Wait 或 WaitAsync 方法,便呼叫一個 Release。
這就好像筆筒裡面的筆,沒有監控,使用這使用完畢後,都應該將筆放進去。如果原先有10支筆,每次使用不放進去,或者將別的地方的筆放進去,那麼最後數量就不是10了。
到此這篇關於C#多執行緒系列之資源池限制的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45