深入分析C# 线程同步

2020-06-17 15:01:08于丽

Interlocked

如果一个变量被多个线程修改,读取。可以用Interlocked

计算机上不能保证对一个数据的增删是原子性的,因为对数据的操作也是分步骤的:

将实例变量中的值加载到寄存器中。 增加或减少该值。 在实例变量中存储该值。

Interlocked为多线程共享的变量提供原子操作。
Interlocked提供了需要原子操作的方法:

public static int Add (ref int location1, int value); 两个参数相加,且把结果和赋值该第一个参数。 public static int Increment (ref int location); 自增。 public static int CompareExchange (ref int location1, int value, int comparand);

location1 和comparand比较,被value替换.

value 如果第一个参数和第三个参数相等,那么就把value赋值给第一个参数。

comparand 和第一个参数对比。

ReaderWriterLock

如果要确保一个资源或数据在被访问之前是最新的。那么就可以使用ReaderWriterLock.该锁确保在对资源获取赋值或更新时,只有它自己可以访问这些资源,其他线程都不可以访问。即排它锁。但用改锁读取这些数据时,不能实现排它锁。

lock允许同一时间只有一个线程执行。而ReaderWriterLock允许同一时间有多个线程可以执行读操作,或者只有一个有排它锁的线程执行写操作。

 class Program
 {
 // 创建一个对象
 public static ReaderWriterLock readerwritelock = new ReaderWriterLock();
 static void Main(string[] args)
 {
  //创建一个线程读取数据
  Thread t1 = new Thread(Write);
  // t1.Start(1);
  Thread t2 = new Thread(Write);
  //t2.Start(2);
  // 创建10个线程读取数据
  for (int i = 3; i < 6; i++)
  {
  Thread t = new Thread(Read);
  // t.Start(i);
  }

  Console.Read();

 }

 // 写入方法
 public static void Write(object i)
 {
  // 获取写入锁,20毫秒超时。
  Console.WriteLine("线程:" + i + "准备写...");
  readerwritelock.AcquireWriterLock(Timeout.Infinite);
  Console.WriteLine("线程:" + i + " 写操作" + DateTime.Now);
  // 释放写入锁
  Console.WriteLine("线程:" + i + "写结束...");
  Thread.Sleep(1000);
  readerwritelock.ReleaseWriterLock();

 }

 // 读取方法
 public static void Read(object i)
 {
  Console.WriteLine("线程:" + i + "准备读...");

  // 获取读取锁,20毫秒超时
  readerwritelock.AcquireReaderLock(Timeout.Infinite);
  Console.WriteLine("线程:" + i + " 读操作" + DateTime.Now);
  // 释放读取锁
  Console.WriteLine("线程:" + i + "读结束...");
  Thread.Sleep(1000);

  readerwritelock.ReleaseReaderLock();

 }
 }
//分别屏蔽writer和reader方法。可以更清晰的看到 writer被阻塞了。而reader没有被阻塞。

//屏蔽reader方法
//线程:1准备写...
//线程:1 写操作2017/7/5 17:50:01
//线程:1写结束...
//线程:2准备写...
//线程:2 写操作2017/7/5 17:50:02
//线程:2写结束...

//屏蔽writer方法
//线程:3准备读...
//线程:5准备读...
//线程:4准备读...
//线程:5 读操作2017/7/5 17:50:54
//线程:5读结束...
//线程:3 读操作2017/7/5 17:50:54
//线程:3读结束...
//线程:4 读操作2017/7/5 17:50:54
//线程:4读结束...