.Net并行编程(3)线程安全与同步机制(锁、信号量)
序言
锁
1.Lock(属于Monitor的语法糖)
lock 关键字是 C# 中最简单和最常用的锁机制,用于在代码块中获取对象的互斥锁,确保同一时间只有一个线程能够执行该代码块。
https://sharplab.io/
2.Monitor
Monitor 类提供了一种更灵活的同步机制,通过 Monitor.Enter 和 Monitor.Exit 方法来获取和释放对象的锁。除了基本的互斥锁外,Monitor 还提供了等待和通知的功能,可以实现更复杂的线程同步方案。
3.Mutex
Mutex 是一种操作系统级别的内核对象,可以用于进程间的同步。在 C# 中,Mutex 类封装了操作系统提供的互斥体,可以用于实现跨进程的线程同步。
4.Semaphore
5.AutoResetEvent和ManualResetEvent
6.ReaderWriterLockSlim
基本规则: 读读不互斥 读写互斥 写写互斥
7.Barrier(屏障同步)
8.spinLock(自旋锁)
我们初识多线程或者多任务时,第一个想到的同步方法就是使用lock或者Monitor,然而在4.0 之后给我们提供了另一把武器spinLock,
如果你的任务持有锁的时间非常短,具体短到什么时候msdn也没有给我们具体的答案,但是有一点值得确定的时,如果持有锁的时候比较
短,那么它比那些重量级别的Monitor具有更小的性能开销,它的用法跟Monitor很相似,
信号量
当出现了并行计算的时候,轻量级别的同步机制应运而生,在信号量这一块出现了一系列的轻量级,今天继续介绍下面的3个信号量 CountdownEvent,SemaphoreSlim,ManualResetEventSlim。
1.CountdownEvent
虽然通过Task.WaitAll()方法也可以达到线程同步的目的。
但是CountdownEvent更牛X之处在于我们可以动态的改变“信号计数”的大小,比如一会儿能够容纳8个线程,一下又4个,一下又10个,CountdownEvent给我们提供了可以动态修改的解决方案。
模拟建房子工序
1 public partial class Form1 : Form 2 { 3 public Form1() 4 { 5 InitializeComponent(); 6 } 7 8 static CountdownEvent cde = null; 9 private void button1_Click(object sender, EventArgs e) 10 { 11 //建房子第一期工人 12 string[] _bhPerson1 = new string[5] { "Yan", "Zhi", "wei", "Do", "Work" }; 13 //建房子第二期工人 14 string[] _bhPerson2 = new string[3] { "Yan2", "Zhi2", "wei2" }; 15 //建房子第三期工人 16 string[] _bhPerson3 = new string[3] { "Yan3", "Zhi3", "wei3" }; 17 using (cde = new CountdownEvent(Environment.ProcessorCount))//开始监管,相当于监工 18 { 19 cde.Reset(_bhPerson1.Length);//设置第一期建造需要5个人 20 foreach (string person in _bhPerson1) 21 { 22 Task.Factory.StartNew(() => 23 { 24 BuilderHourseStep1(person); 25 }); 26 27 } 28 cde.Wait();//等待第一期建造完成 29 Console.WriteLine("-----------------------"); 30 31 cde.Reset(_bhPerson2.Length);//设置第二期建需要三个人 32 foreach (string person in _bhPerson2) 33 { 34 Task.Factory.StartNew(() => 35 { 36 BuilderHourseStep2(person); 37 }); 38 } 39 cde.Wait();//等待第二期建造完成 40 Console.WriteLine("-----------------------"); 41 42 cde.Reset(_bhPerson3.Length);//设置第三期建需要三个人 43 foreach (string person in _bhPerson3) 44 { 45 Task.Factory.StartNew(() => 46 { 47 BuilderHourseStep3(person); 48 }); 49 } 50 cde.Wait();//等待第三期建造完成 51 Console.WriteLine("-----------------------"); 52 } 53 } 54 /// <summary> 55 /// 建房子第一道所需要的工序 56 /// </summary> 57 /// <param name="person"></param> 58 static void BuilderHourseStep1(string person) 59 { 60 try 61 { 62 Console.WriteLine(string.Format("『{0}』BuilderHourseStep1....", person)); 63 } 64 finally 65 { 66 cde.Signal();//建造完成一点后,通知监工 67 } 68 } 69 /// <summary> 70 /// 建房子第二道所需要的工序 71 /// </summary> 72 /// <param name="person"></param> 73 static void BuilderHourseStep2(string person) 74 { 75 try 76 { 77 Console.WriteLine(string.Format("『{0}』BuilderHourseStep2.....", person)); 78 } 79 finally 80 { 81 cde.Signal(); 82 } 83 } 84 /// <summary> 85 /// 建房子第三道所需要的工序 86 /// </summary> 87 /// <param name="person"></param> 88 static void BuilderHourseStep3(string person) 89 { 90 try 91 { 92 Console.WriteLine(string.Format("『{0}』BuilderHourseStep3.......", person)); 93 } 94 finally 95 { 96 cde.Signal(); 97 } 98 } 99 }
分步执行任务
1 static void Main(string[] args) 2 { 3 IList<string> taskList =new List<string> {"任务一","任务二", "任务四", "任务五", "任务六" }; 4 int count = taskList.Count; 5 using (CountdownEvent cde = new CountdownEvent(Environment.ProcessorCount)) 6 { 7 cde.Reset(count);//设置信号数 8 foreach (var item in taskList) 9 { 10 Task.Factory.StartNew(() => 11 { 12 Console.WriteLine("处理任务:"+item); 13 cde.Signal();//每次调用 Signal 时,信号计数都会递减 1。 14 }); 15 } 16 cde.Wait();// 在主线程上,对 Wait 的调用将会阻塞,直至信号计数为零。 17 Console.WriteLine("接下来开始做下一件事情"); 18 cde.Reset(count);//重置信号数 19 foreach (var item in taskList) 20 { 21 Task.Factory.StartNew(() => 22 { 23 Console.WriteLine("继续处理任务:" + item); 24 cde.Signal();//每次调用 Signal 时,信号计数都会递减 1。 25 }); 26 } 27 } 28 Console.ReadKey(); 29 }
2.SemaphoreSlim
3.ManualResetEventSlim
线程安全的集合
ConcurrentBag
BlockingCollection
ConcurrentDictionary
ConcurrentQueue
ConcurrentStack
资料
https://www.bilibili.com/video/BV1Cw411A7Fr/?spm_id_from=333.788&vd_source=a56db24cb8cab4dd8153f9a519787c89
https://sharplab.io/
https://www.cnblogs.com/huangxincheng/archive/2012/04/07/2437110.html
http://blog.gkarch.com/threading/part5.html#the-parallel-class
http://www.cnblogs.com/huangxincheng/archive/2012/04/08/2437701.html
http://www.cnblogs.com/yaopengfei/p/8315212.html