一提到Semaphore(信号量)的使用,还挺有意思的,它允许多个线程同时访问多个稀有资源,我立马想到银行的ATM机取钱的场景。看下面的代码:
static Semaphore sem = new Semaphore(2, ); public static void StartThread(string name)
{
var t = new Thread(run);
t.Name = name;
t.Start();
}
static void run()
{
string name = Thread.CurrentThread.Name;
Console.WriteLine(name + "正在等待ATM小房子……");
//申请一个许可证
sem.WaitOne();
Console.WriteLine(name + "进入ATM小房子……");
Console.WriteLine(name + "开始操作ATM");
Thread.Sleep();
Console.WriteLine(name + "操作ATM结束");
Console.WriteLine(name + " 从ATM小房子出来了……");
//释放
sem.Release();
}
static void Main(string[] args)
{
for (int i = ; i < ; i++)
{
StartThread("#" + (i + ));
}
Console.Read();
}
Semaphore构造函数,第一个参数表示当前可用资源数,第二个参数表示最大资源数。可用资源数不能超过最大资源数,否则c#运行时会抛出异常。当初始资源为0时,看看结果:
这个结果说明,4个ATM,当前都有人占用着,所以四个人处于等待状态。
当我们把初始资源数设为4,结果:
上图说明,四个人都没有等待,而是直接进入了ATM机的小房子。当资源足够用的时候,就不存在稀缺资源这么一说了。
当我们把初始资源数设为1时,再次看看结果:
当我们把资源数设置为1时,这时候不就和互斥体产生的效果一样了吗?这就好比众多的病人在一个诊室等着看病一样,医生只能一个一个地来。
总之,信号量内部维护了一个对稀有资源的计数器,当一个资源被用时(调用WaitOne方法,一直阻塞线程,直到有可用资源),这个计数器-1,当一个资源被释放(调用Release方法)时,这个计数器+1,如果计数器为0时,表示资源耗尽了,那么所有线程都处于等待状态。