标签:
场景:当多个任务或线程并行运行时,难以避免的对某些有限的资源进行并发的访问
可以考虑使用信号量来进行这方面的控制(System.Threading.Semaphore)是表示一个Windows内核的信号量对象(操作系统级别,可以跨进程或AppDomain)。如果预计等待的时间较短,使用SemaphoreSlim(单进程)带来的开销更小。关于两者的区别如下:
System.Threading.Semaphore 类表示一个命名(系统范围内)或本地信号量。它是环绕 Win32 信号量对象的精简包装器。Win32 信号量是计数信号量,该可用于控制对资源池的访问。
SemaphoreSlim 类表示一个轻量、快速的信号量,可在等待时间预计很短的情况下用于在单个进程内等待。 SemaphoreSlim 尽可能多地依赖公共语言运行时 (CLR) 提供的同步基元。但是,它还提供延迟初始化、基于内核的等待句柄,作为在多个信号量上进行等待的必要支持。 SemaphoreSlim 也支持使用取消标记,但不支持命名信号量或使用用于同步的等待句柄。
这里我们只讨论System.Threading.Semaphore,.Net FrameWork中的信号量通过跟踪进入和离开的任务或线程来协调对资源的访问。信号量需要知道资源的最大数量,当一个任务进入时,资源计数器会被减1(获取到访问许可证),当计数器为0时,如果有任务访问资源(未被授权访问许可证),它会被阻塞,直到有任务离开为止。
介绍一下Semaphore这个类的常用的初始化构造方法,如下,请仔细阅读注释部分。
/// <summary> /// Initializes a new instance of the <see cref="T:System.Threading.Semaphore"/> class, specifying the maximum number of concurrent entries and optionally reserving some entries. /// </summary> /// <param name="initialCount">The initial number of requests for the semaphore that can be granted concurrently.</param><param name="maximumCount">The maximum number of requests for the semaphore that can be granted concurrently.</param><exception cref="T:System.ArgumentException"><paramref name="initialCount"/> is greater than <paramref name="maximumCount"/>.</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="maximumCount"/> is less than 1.-or-<paramref name="initialCount"/> is less than 0.</exception> [SecuritySafeCritical] [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] public Semaphore(int initialCount, int maximumCount);
initialCount:信号量可以接受的并发请求数量的初始值
maximumCount:信号量可以接受的并发请求数量的最大值
那么看下面这个demo。
1 class Program 2 { 3 //创建一个可授权2个许可证的信号量,且初始值为2 4 static Semaphore _semaphore = new Semaphore(2, 2); 5 6 static void Main(string[] args) 7 { 8 Task.Factory.StartNew(() => DoWork()); 9 Task.Factory.StartNew(() => DoWork()); 10 Task.Factory.StartNew(() => DoWork()); 11 12 Console.ReadLine(); 13 } 14 15 static void DoWork() 16 { 17 try 18 { 19 Console.WriteLine(string.Format("Thread {0} 正在等待一个许可证……", Thread.CurrentThread.ManagedThreadId)); 20 _semaphore.WaitOne(); 21 Console.WriteLine(string.Format("Thread {0} 申请到许可证……", Thread.CurrentThread.ManagedThreadId)); 22 Thread.Sleep(5000); 23 Console.WriteLine(string.Format("Thread {0} 释放许可证……", Thread.CurrentThread.ManagedThreadId)); 24 } 25 finally 26 { 27 _semaphore.Release(); 28 } 29 } 30 }
多个线程申请获取许可证,其中线程A通过_semaphore.WaitOne拿到了一个许可证,进行initialCount-1操作,业务完成之后再调用_semaphore.Release释放了这个许可证,initialCount+1。如果设置最大并发数=1,那么当前仅有1个线程能够拿到这个许可,其他线程都处于阻塞状态,直到该线程释放为止。当然信号量不可能永久的阻塞在那里。信号量也提供了超时处理机制。方法是在Wait函数中传入一个超时等待时间 - Wait(int TIMEOUT)。当Wait返回值为false时表明它超时了。如果传入了 -1,则表示无限期的等待。
关于信号量和锁/队列的概念
信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,也是操作系统用来控制等待一种机制 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。
互斥量(Mutex) ,互斥量表现互斥现象的数据结构,也被当作二元信号灯。一个互斥基本上是一个多任务敏感的二元信号,它能用作同步多任务的行为,它常用作保护从中断来的临界段代码并且在共享同步使用的资源。
Mutex本质上说就是一把锁,提供对资源的独占访问,所以Mutex主要的作用是用于互斥。Mutex对象的值,只有0和1两个值。这两个值也分别代表了Mutex的两种状态。值为0, 表示锁定状态,当前对象被锁定,用户进程/线程如果试图Lock临界资源,则进入排队等待;值为1,表示空闲状态,当前对象为空闲,用户进程/线程可以Lock临界资源,之后Mutex值减1变为0。
Enqueue和Lock实际上是一个事物的两个名字。他们都支持队列(queue)和并发(concurrency)。他们在队列中的管理方式是“先进先出”(FIFO)的方式。
标签:
原文地址:http://www.cnblogs.com/Mushrooms/p/5122187.html