C# Semaphore 信号量 锁 简单理解
信号量(Semaphore)
Semaphore 一般译作 信号量,它也是一种线程同步工具,主要用于多个线程对共享资源进行并行操作的一种工具类。它代表了一种许可的概念,是否允许多线程对同一资源进行操作的许可,使用 Semaphore 可以控制并发访问资源的线程个数。
信号量(Semaphore)概念解释
信号量就是一个停车场。
当前值是停车场里还剩下多少个空车位。
最大值是停车场里最多能容纳多少个车位。
当汽车进入停车场时,首先要在门口排队(sem_wait),得到进入许可后才能进入。
排队顺序原则上先到先得。
每进一辆车,停车场就少了1个停车位,即信号量当前值-1。
当前值为0时,停车场停满了,所有车不得进入统统在门口排队等。
当一辆车离开后,释放其所占据的停车位(sem_post),信号量当前值+1
信号量值得到释放后,如果门口有正在排队的车,那么就放进来,每放进来一个就重复前面的步骤。
例子:Semaphore(1, 4): 当前停车场有4个车位。里面默认已经停了一辆车了。 WaitOne() 表示一个车再停车场内等待,车位-1 Release(N)表示一辆车离开停车场,车位+1; 当车位为0是。表示已经停满车。Semaphore 的使用场景
1、主要用于流量控制,比如数据库连接,同时使用的数据库连接会有数量限制,数据库连接不能超过一定的数量,当连接到达了限制数量后,后面的线程只能排队等前面的线程释放数据库连接后才能获得数据库连接。
2、 信号量:是进程间(线程间)同步用的,一个进程(线程)完成了某一个动作就通过信号量告诉别的进程(线程),别的进程(线程)再进行某些动作。有二值和多值信号量之分。
它与的互斥锁区别是 互斥锁:是线程间互斥用的,一个线程占用了某一个共享资源,那么别的线程就无法访问,直到这个线程离开,其他的线程才开始可以使用这个共享资源。可以把互斥锁看成二值信号量。
引发的问题
信号量存在的优先级翻转问题优先级反转,是指在使用信号量时,可能会出现的这样一种不合理的现象,即:
高优先级任务被低优先级任务阻塞,导致高优先级任务迟迟得不到调度。但其他中等优先级的任务却能抢到CPU资源。-- 从现象上来看,好像是中优先级的任务比高优先级任务具有更高的优先权。
具体来说:当高优先级任务正等待信号量(此信号量被一个低优先级任务拥有着)的时候,一个介于两个任务优先之间的中等优先级任务开始执行——这就会导致一个高优先级任务在等待一个低优先级任务,而低优先级任务却无法执行类似死锁的情形发生。
主要方法
Semaphore(1, 4):默认运行信号量之后就可以释放一条线程进入临界资源。手动设置Release的一次最大个数是4条线程,临界区最大的线程数是4.当一次释放的线程超过等待的资源数就会报错
WaitOne()阻塞线程,等灯来
Release(N) 同时放行条线程进入资源区,最大不能超过初始化设定的maximumCount
Close()释放所有
使用方式1
有10个线程,同时只执行4条线程,每完成一个就Release一个,等待中的就补上去
代码如下:
该代码会正常执行完成,并且释放所有线程,因为初始化话new Semaphore(1, 4)时候已经设置默认释放一条线程,这条线程执行完成后road.Release();又释放下一条。依次释放完所有线程。
Semaphore road = new Semaphore(1, 4); for(int i = 0; i < 10; i++) { new Thread(obj => { int se = (int)obj; Console.WriteLine(se); road.WaitOne(); Console.WriteLine("release{0}",obj); road.Release();//该线程执行完毕,后再释放一个线程 } ).Start(i); } Thread.Sleep(1000); //该代码会正常执行完成,并且释放说有线程,因为初始化话new Semaphore(1, 4)时候已经设置默认释放一条线程,这条线程执行完成后road.Release();又释放下一条。依次释放完所有线程。
另外,信号量是内核对象可以再多个进程中使用。可以给信号量设置一个名称,这个名称是操作系统可见的,因此,可以使用这些信号量来协调跨进程边界的资源使用。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace Semaphore2 { class Program { static void Main(string[] args) { Semaphore seamphore = new Semaphore(5, 5, "SemaphoreExample"); seamphore.WaitOne(); Console.WriteLine("Seamphore 1"); seamphore.WaitOne(); Console.WriteLine("Seamphore 2"); seamphore.WaitOne(); Console.WriteLine("Seamphore 3"); Console.ReadLine(); seamphore.Release(3); } } } 复制代码
运行两个这样的程序,你讲看到这样的结果,在第二个运行的示例中,会将线程阻塞在第三个信号量