任务,线程和同步(七)之同步其他些类

来源:互联网 发布:docker overlay网络 编辑:程序博客网 时间:2024/06/02 02:08

同步

要避免同步问题,最好不要在线程之间共享数据。当然,这并不总是可行的。如果需要共享数据,就必须使用同步技术,确保一次只有一个线程访问和改变共享状态。注意,同步问题与争用条件和死锁有关。如果不注意这些问题,就很难在应用程序中找到问题的原因,因为线程问题是不定期发生的。

1.lock语句和线程安全

C#为多线程的同步提供了自己的关键字:lock语句。lock语句是设置锁定和解除锁定的一种简单方式。在添加lock之前先进入另一个争用条件。

注: 在一个地方使用lock语句并不意味着,访问对象的其他线程都正在等待。必须对每个访问共享状态的线程显式地使用同步功能

其他相关信息查看:C#中的lock关键字

2.Interlocked类

Interlocked用于使变量的简单语句原子化。i++不是线程安全的,它的操作包括从内存中获取一个值,给该值递增1,再将它存储回内存。这些操作都可能会被线程调度器打断。Interlocked类提供了以线程安全的方式递增,递减,交换和读取值的方法。
与其他同步技术相比,使用Interlocked类会快的多。但是,它只能简单的同步问题。

其他相关信息查看:.NET中保证线程安全的高级方法Interlocked类使用介绍

3.Monitor类

lock语句由C#编译器解析为使用Monitor类。
被解析为 调用Enter方法,该方法会一直等待,知道线程锁定对象为止。一次只有一个线程能锁定对象。只要解除了锁定,线程就可以进入同步阶段。Monitor类的exit方法解除锁定。编译器会把exit方法放在try块的finally处理程序中,所以如果抛出异常,就也会解除该锁定。

         public void Monitor1(object obj)        {            bool lockTaken=false;            Monitor.TryEnter(obj, 500,ref lockTaken);           // Monitor.Enter(obj);            try            {            }            finally            {                Monitor.Exit(obj);            }        }

Monitor类主要优点:可以添加一个等待被锁定的超时值。这样就不会无限期地等待被锁定。如果obj被锁定,TryEnter方法就把布尔类型的引用参数设置为true,并同步地访问由对象obj锁定的状态。如果另一个线程锁定obj超过了500毫秒。TryEnter方法变量lockTaken设置为false,线程不再等待,而是执行其他操作。也许在以后,该线程会尝试再次获得锁定。

其他相关信息查看:C#知识点总结系列:4、C#中Monitor和Lock以及区别

4.SpinLock结构

如果基于对象的锁定对象Monitor的系统开销由于垃圾回收过高,就可以使用SpinLock结构。在.NET 4 开始引入的。如果有大量的锁定且锁定的事件总是非常短,SpinLock结构就很有用。应避免使用多个SpinLock结构,也不要调用可能的阻塞的内容。

除了体系结构上的区别之外,SpinLock结构的用法非常类似于Monitor类。获得锁定使用Enter或tryenter方法,释放锁定使用exit方法。SpinLock结构还提供看属性IsHeld和IsHeldByCurrentThread,指定它当前是否是锁定的。

注:传送SpinLock实例时要小心,因为SpinLock定义结构,把一个变量赋予另一个变量会创建一个副本。总是通过引用传送SpinLock实例。

其他相关信息查看:C#多线程编程中的锁系统(四):自旋锁

5.WaitHandle基类

WaitHandle是一个抽象的基类,用于等待一个信号的设置。可以等待不同的信号,它可以派生一些类。

异步委托的BeginInvoke方法返回一个实现IAsycResult接口对象。使用IAsycResult接口,可用用AsycWaitHandle属性访问WaitHandle基类。在调用WaitOne方法时,线程会等待接受一个与等待句柄相关的信号

其他相关信息查看: c# WaitHandle类在线程池ThreadPool(超过64个线程时)中的使用方法

6.Mutex类

Mutex(互斥)是NET Framework中提供跨多个进程同步访问一个类。它非常类似于Monitor类,因为它们都是只有一个线程能锁定的。只有一个进程能获得互斥锁定,访问受互斥保护的同步代码区域。

其他相关信息查看:C# Mutex对象的使用

7.Semaphore类

信号量非常类似于互斥,其区别是,信号量可以同时由多个线程使用。信号量是一种计数的互斥锁定。使用信号量,可以定义允许同时访问受其锁定保护的资源的线程个数。如果需要限制访问线程的个数,信号量很有用。

信号量功能提供了2个类Semaphore和SemaphoreSlim。

  • Semaphore类可以命名,使用系统范围内的资源,允许在不同进程之间同步。
  • SemaphoreSlim类是对较短等待时间进行优化的轻型版本

其他相关信息查看:c# Semaphore(信号量)

8.Event类

与互斥和信号量一样,事件也是一个系统范围 内的资源同步方法。为了从托管代码中使用系统事件,System.Threading命名空间提供了ManualResetEvent,AutoResetEvent,ManualResetSlim和CountDownEvent类。

这里写图片描述

这里写图片描述

其他相关信息查看:C#事件(event)解析

9.Barrier类

对于同步,Barrier类非常适用于其中工作有多个任务分支且以后又要合并的情况。Barrier类用于需要同步的参与者。激活一个任务时,就可以动态的添加其他参与者,例如,从父任务中创建子任务。参与者在继续之前,可以等待所有其他参与者完成其工作。

其他相关信息查看: C# 并行编程 之 Barrier的使用 - 通过屏障同步并发任务

10.ReadWriterLockSlim类

为了使锁定机制允许锁定多个读取器(而不是一个写入器)访问某个资源,可以使用ReadWriterLockSlim类。这个类提供了一个锁定功能,如果没有写入器锁定资源,就允许多个读取器访问资源,但只能有一个写入器锁定该资源。
ReadWriterLockSlim类属性可以获得读取阻塞或不阻塞的锁定,如:EnterReadLock和TryEnterReadLock方法。还可使用EnterWriteLock和TryEnterWriteLock方法取得写入锁定。如果任务先读取资源,之后写入资源,他就可以使用EnterUpgradableReadLock或TryEnterUpgradableReadLock方法获取可升级的读取锁定。有了 这个锁定,就可以获取写入锁定,而无须释放读取锁定。

其他相关信息查看: 如何使用C#读写锁ReaderWriterLockSlim

0 0
原创粉丝点击