C#资源池限制实例分析
这篇“C#资源池限制实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C#资源池限制实例分析”文章吧。
Semaphore、SemaphoreSlim 类两者都可以限制同时访问某一资源或资源池的线程数。
Semaphore 类这里,先列出 Semaphore 类常用的 API。
其构造函数如下:
Semaphore 使用纯粹的内核时间(kernel-time)方式(等待时间很短),并且支持在不同的进程间同步线程(像Mutex)。
Semaphore 常用方法如下:
我们来直接写代码,这里使用 《原子操作 Interlocked》 中的示例,现在我们要求,采用多个线程执行计算,但是只允许最多三个线程同时执行运行。
使用 Semaphore ,有四个个步骤:
new 实例化 Semaphore,并设置最大线程数、初始化时可进入线程数;
使用.WaitOne();
获取进入权限(在获得进入权限前,线程处于阻塞状态)。
离开时使用Release()
释放占用。
Close()
释放Semaphore 对象。
《原子操作 Interlocked》 中的示例改进如下:
classProgram{//求和privatestaticintsum=0;privatestaticSemaphore_pool;//判断十个线程是否结束了。privatestaticintisComplete=0;//第一个程序staticvoidMain(string[]args){Console.WriteLine("执行程序");//设置允许最大三个线程进入资源池//一开始设置为0,就是初始化时允许几个线程进入//这里设置为0,后面按下按键时,可以放通三个线程_pool=newSemaphore(0,3);for(inti=0;i<10;i++){Threadthread=newThread(newParameterizedThreadStart(AddOne));thread.Start(i+1);}Console.ForegroundColor=ConsoleColor.Red;Console.WriteLine("任意按下键(不要按关机键),可以打开资源池");Console.ForegroundColor=ConsoleColor.White;Console.ReadKey();//准许三个线程进入_pool.Release(3);//这里没有任何意义,就单纯为了演示查看结果。//等待所有线程完成任务while(true){if(isComplete>=10)break;Thread.Sleep(TimeSpan.FromSeconds(1));}Console.WriteLine("sum="+sum);//释放池_pool.Close();}publicstaticvoidAddOne(objectn){Console.WriteLine($"线程{(int)n}启动,进入队列");//进入队列等待_pool.WaitOne();Console.WriteLine($"第{(int)n}个线程进入资源池");//进入资源池for(inti=0;i<10;i++){Interlocked.Add(refsum,1);Thread.Sleep(TimeSpan.FromMilliseconds(500));}//解除占用的资源池_pool.Release();isComplete+=1;Console.WriteLine($"第{(int)n}个线程退出资源池");}}
看着代码有点多,快去运行一下,看看结果。
示例说明实例化 Semaphore 使用了new Semaphore(0,3);
,其构造函数原型为
publicSemaphore(intinitialCount,intmaximumCount);
initialCount 表示一开始允许几个进程进入资源池,如果设置为0,所有线程都不能进入,要一直等资源池放通。
maximumCount 表示最大允许几个线程进入资源池。
Release()
表示退出信号量并返回前一个计数。这个计数指的是资源池还可以进入多少个线程。
可以看一下下面的示例:
privatestaticSemaphore_pool;staticvoidMain(string[]args){_pool=newSemaphore(0,5);_pool.Release(5);newThread(AddOne).Start();Thread.Sleep(TimeSpan.FromSeconds(10));_pool.Close();}publicstaticvoidAddOne(){_pool.WaitOne();Thread.Sleep(1000);intcount=_pool.Release();Console.WriteLine("在此线程退出资源池前,资源池还有多少线程可以进入?"+count);}信号量
前面我们学习到 Mutex,这个类是全局操作系统起作用的。我们从 Mutex 和 Semphore 中,也看到了 信号量这个东西。
信号量分为两种类型:本地信号量和命名系统信号量。
命名系统信号量在整个操作系统中均可见,可用于同步进程的活动。
局部信号量仅存在于进程内。
当 name 为 null 或者为空时,Mutex 的信号量时局部信号量,否则 Mutex 的信号量是命名系统信号量。
Semaphore 的话,也是两种情况都有。
如果使用接受名称的构造函数创建 Semaphor 对象,则该对象将与该名称的操作系统信号量关联。
两个构造函数:
Semaphore(Int32,Int32,String)Semaphore(Int32,Int32,String,Boolean)
上面的构造函数可以创建多个表示同一命名系统信号量的 Semaphore 对象,并可以使用 OpenExisting 方法打开现有的已命名系统信号量。
我们上面使用的示例就是局部信号量,进程中引用本地 Semaphore 对象的所有线程都可以使用。 每个 Semaphore 对象都是单独的本地信号量。
SemaphoreSlim类SemaphoreSlim 跟 Semaphore 有啥关系?
微软文档:
SemaphoreSlim 表示对可同时访问资源或资源池的线程数加以限制的 Semaphore 的轻量替代。
SemaphoreSlim 不使用信号量,不支持进程间同步,只能在进程内使用。
它有两个构造函数:
我们改造一下前面 Semaphore 中的示例:
classProgram{//求和privatestaticintsum=0;privatestaticSemaphoreSlim_pool;//判断十个线程是否结束了。privatestaticintisComplete=0;staticvoidMain(string[]args){Console.WriteLine("执行程序");//设置允许最大三个线程进入资源池//一开始设置为0,就是初始化时允许几个线程进入//这里设置为0,后面按下按键时,可以放通三个线程_pool=newSemaphoreSlim(0,3);for(inti=0;i<10;i++){Threadthread=newThread(newParameterizedThreadStart(AddOne));thread.Start(i+1);}Console.WriteLine("任意按下键(不要按关机键),可以打开资源池");Console.ReadKey();//_pool.Release(3);//这里没有任何意义,就单纯为了演示查看结果。//等待所有线程完成任务while(true){if(isComplete>=10)break;Thread.Sleep(TimeSpan.FromSeconds(1));}Console.WriteLine("sum="+sum);//释放池}publicstaticvoidAddOne(objectn){Console.WriteLine($"线程{(int)n}启动,进入队列");//进入队列等待_pool.Wait();Console.WriteLine($"第{(int)n}个线程进入资源池");//进入资源池for(inti=0;i<10;i++){Interlocked.Add(refsum,1);Thread.Sleep(TimeSpan.FromMilliseconds(200));}//解除占用的资源池_pool.Release();isComplete+=1;Console.WriteLine($"第{(int)n}个线程退出资源池");}}
SemaphoreSlim 不需要Close()
。
两者在代码上的区别是就这么简单。
区别如果使用下面的构造函数实例化 Semaphor(参数name不能为空),那么创建的对象在整个操作系统内都有效。
publicSemaphore(intinitialCount,intmaximumCount,stringname);
Semaphorslim 则只在进程内内有效。
SemaphoreSlim 类不会对Wait
、WaitAsync
和Release
方法的调用强制执行线程或任务标识。
而 Semaphor 类,会对此进行严格监控,如果对应调用数量不一致,会出现异常。
此外,如果使用 SemaphoreSlim(Int32 maximumCount) 构造函数来实例化 SemaphoreSlim 对象,获取其 CurrentCount 属性,其值可能会大于 maximumCount。 编程人员应负责确保调用一个 Wait 或 WaitAsync 方法,便调用一个 Release。
这就好像笔筒里面的笔,没有监控,使用这使用完毕后,都应该将笔放进去。如果原先有10支笔,每次使用不放进去,或者将别的地方的笔放进去,那么最后数量就不是10了。
以上就是关于“C#资源池限制实例分析”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注亿速云行业资讯频道。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。