标签:ica lse 改进 交换 分时 inter 更改 包括 task
当多个线程共享一些数据的时候,我们就需要使用同步技术,确保一次只有一个线程访问合改变共享状态。注意,同步问题与争用和死锁有关。
例:
static int idx = 0; static void Add() { for (int i = 0; i < 50000; i++) { idx++; } } static void Main() { const int SIZE = 40; Task[] arr = new Task[SIZE]; while (true) { for (int i = 0; i < SIZE; i++) { arr[i] = new Task(Add); arr[i].Start(); //启动多个线程 } for (int i = 0; i < SIZE; i++) { arr[i].Wait(); //等待线程完成 } Console.WriteLine(idx); Thread.Sleep(500); idx = 0;// 重置数据,再次运行 } }
结果:
1717634
1652989
1444839
1272385
1558097
1297459
1968232
2000000
显然,不是我们想要的,我们期望每次运行的结果都是2000000。这是因为idx++不是线程安全的,它的操作包括从内存中获取一个值,给该值递增1,再将它存回内存。这些操作都可能会被线程调度器打断。
这种情况下,我们就需要一些同步方法解决该问题。
static object locker = new object(); static void Add() { for (int i = 0; i < 50000; i++) { lock (locker) idx++; } }
对上例而言,把idx++替换成Interlocked.Increment(ref idx);
lock(obj) { //synchronized region for obj } 相当于 Monitor.Enter(obj); try { //synchornized region for obj } finally { Monitor.Exit(obj) }
用TryEnter可以添加timeout
1 object obj = new object(); 2 Task.Run(()=>{ 3 lock(obj) 4 { 5 Console.WriteLine("lock obj"); 6 Thread.Sleep(3000); 7 } 8 }); 9 bool b = Monitor.TryEnter(obj, 2000); 10 if (b) 11 { 12 try 13 { 14 Console.WriteLine("monitor enter."); 15 } 16 finally 17 { 18 Monitor.Exit(obj); 19 } 20 } 21 else 22 { 23 Console.WriteLine("monitor enter false."); 24 } 25 26 Console.ReadKey();
另外,Monitor还提供了Wait方法,用于释放对象上的锁并阻止当前线程,直到它重新获取该锁。
提供了Pulse方法用于通知等待队列中的线程锁定对象状态的更改;PulseAll通知所有的等待线程对象状态的更改。
请不要在存储 SpinLock 只读字段中的实例。
标签:ica lse 改进 交换 分时 inter 更改 包括 task
原文地址:https://www.cnblogs.com/wrbxdj/p/8554876.html