根據同時是否允許複數的執行緒存取 critical section 可分為 exclusive 和 shared 兩類
Exclusive
指一次只能有一個 thread 進入。
lock=Monitor、Mutex、Other EventWaitHandle
Shared
一次可以有指定數量的 threads 進入。
Semaphore、ReadWriteLock
lock and Monitor
基本上 lock(){}就是
的語法糖,如果沒有要用 Monitor.TryEnter() 設 timeout 的話都用 lock{}就可以。
- var temp = obj;
- Monitor.Enter(temp);
- try
- {
- body
- }
- finally
- {
- Monitor.Exit(temp);
- }
Mutex
以下是用作鎖的例子並附上同屬 EventWaitHandle 的 AutoResetEvent 交互參考,基本上 Mutex 的主要用途是跨 Processes 同步,沒有此需求就不要用它浪費資源了。
- //static AutoResetEvent _ewh = new AutoResetEvent(true);
- static Mutex _mut = new Mutex();
- static bool _taken = false;
- static void Main()
- {
- for (int i = 0; i < 5; i++)
- {
- Task.Run(async () =>
- {
- await Task.Delay(new Random().Next(100, 500));
- Take();
- });
- }
- Console.ReadLine();
- }
- private static void Take()
- {
- //_ewh.WaitOne();
- _mut.WaitOne();
- if (_taken)
- {
- Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} attempt failed, resource was taken");
- }
- else
- {
- _taken = true;
- Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} took the resource");
- }
- //_ewh.Set();
- _mut.ReleaseMutex();
- }
Semaphore
這個跟 ReadWriteLock 都有 Slim 版,Slim 版不能跨 Processes,但資源消耗較小,一般會用 Slim 版。 用法類似 WaitHandle,但建構式處可指定進入緒的數量。
我一直覺得 WaitHandle 這個家族的用法語意很差,但不知道為什麼很多類都是參考這個風格做的,搞得多緒每次寫每次查。
- static SemaphoreSlim sphs = new SemaphoreSlim(3);
- static BlockingCollection<string> resources = new BlockingCollection<string>() { "res1", "res2", "res3", "res4", "res5", "res6", "res7", "res8", "res9" };
- static void Main()
- {
- var resCount = resources.Count;
- for (int i = 0; i < resCount; i++)
- {
- Task.Run(async () =>
- {
- await Take();
- });
- }
- Console.ReadLine();
- }
- private async static Task Take()
- {
- Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} is waiting");
- sphs.Wait();
- if (resources.Any())
- {
- var res = resources.Take();
- Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} takes the {res}");
- }
- else
- {
- Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} attempt failed, all resources was taken");
- }
- await Task.Delay(new Random().Next(500, 1000));
- Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} released");
- sphs.Release();
- }
ref: 亞斯狼(鎖差別一覽表)
沒有留言:
張貼留言