关于锁,我们经常会使用lock object对象,进行资源访问的限制。
但,lock是有限制的,无法添加异步方法。编译器会报错。
下面推荐另一个类SemaphoreSlim,这是信号量的一个使用类。先看下面的使用:
1 private async void MainWindow_Loaded(object sender, RoutedEventArgs e) 2 { 3 var tasks = new List<Task>(); 4 for (int i = 0; i < 10; i++) 5 { 6 var message = $"message{i}"; 7 tasks.Add(Task.Run(async () => 8 { 9 await LockWithSemaphore(message); 10 })); 11 } 12 await Task.WhenAll(tasks); 13 } 14 private SemaphoreSlim _asyncLock = new SemaphoreSlim(1); 15 async Task LockWithSemaphore(string title) 16 { 17 Console.WriteLine($"{title} waiting for lock"); 18 await _asyncLock.WaitAsync(); 19 20 Console.WriteLine($"{title} starting"); 21 await Task.Delay(200); 22 Console.WriteLine($"{title} ending"); 23 24 _asyncLock.Release(); 25 }
输出结果:
从控制台结果可以看出,SemaphoreSlim 完美的完成了异步场景下的锁操作,严格的保持了并发操作的互斥。
SemaphoreSlim类,从源码来看,内部其实是使用了ManualResetEvent:
关于信号锁,常用的有AutoResetEvent和ManualResetEvent,在线程同异步处理场景下比较常见。
SemaphoreSlim,能做的事还有很多,比如:
1. 下载并发时,限制下载并行数量为5个。我们就可以通过设置SemaphoreSlim为5来实现。
2. 访问数据库、或者硬件设备时,需要限制访问数量为1。