CL奥迪Q7线程池并不会在CLCRUISER初步化时即时创建线程,而是在应用程序要创立线程来运转职分时,线程池才起初化八个线程。
线程池起头化时是平昔不线程的,线程池里的线程的初始化与别的线程壹样,可是在做到职务之后,该线程不会自动销毁,而是以挂起的事态再次回到到线程池。直到应用程序再一次向线程池发出请求时,线程池里挂起的线程就会重新激活执行任务。
那样既节省了建立线程所造成的性格损耗,也得以让多个职责反复重用同1线程,从而在应用程序生存期内节约大批量开发。

前几天大家来谈谈线程池:

  干什么使用线程池?  

异步编制程序:使用线程池管理线程,异步线程

异步编制程序:使用线程池管理线程

金沙注册送58 1

 从此图中我们会意识 .NET 与C#
的各种版本揭橥都以有二个“核心”。即:C#1.0托管代码→C#2.0泛型→C#3.0LINQ→C#4.0动态语言→C#伍.0异步编制程序。今后我为流行版本的“异步编程”核心写连串分享,期待您的查看及点评。

 

近年来的应用程序越来越复杂,大家日常必要采纳《异步编制程序:线程概述及选用》中提到的三十二线程技术来增强应用程序的响应速度。这时我们反复的成立和销毁线程来让应用程序神速响应操作,那频仍的创建和销毁无疑会回落应用程序质量,大家得以引入缓存机制消除那一个难点,此缓存机制亟待缓解如:缓存的大小难点、排队执行任务、调度空闲线程、按需成立新线程及销毁多余空闲线程……近来微软早已为大家提供了现成的缓存机制:线程池

        
线程池原自于对象池,在事无巨细表达明线程池前让大家先来询问下何为对象池。

流程图:

 金沙注册送58 2

 

         对于对象池的清理平常设计二种办法:

一)         手动清理,即积极调用清理的主意。

二)         自动清理,即因而System.Threading.Timer来达成定时清理。

 

重中之重完毕代码:

 

  金沙注册送58 3public
sealed class ObjectPool<T> where T : ICacheObjectProxy<T> {
// 最大体积 private Int3二 m_maxPoolCount = 30; // 最小容积 private
Int3贰 m_minPoolCount = 五; // 已存容积 private Int3二 m_currentCount; //
空闲+被用 对象列表 private Hashtable m_listObjects; // 最大空闲时间
private int maxIdle提姆e = 120; // 定时清理对象池指标 private Timer timer
= null; /// <summary> /// 创立对象池 /// </summary> ///
<param name=”maxPoolCount”>最小体积</param> /// <param
name=”minPoolCount”>最大体量</param> /// <param
name=”create_params”>待创制的骨子里目的的参数</param> public
ObjectPool(Int3二 maxPoolCount, Int3二 minPoolCount, Object[]
create_params){ } /// <summary> /// 获取贰个对象实例 ///
</summary> ///
<returns>重返内部实际目的,若重返null则线程池已满</returns>
public T GetOne(){ } /// <summary> /// 释放该指标池 ///
</summary> public void Dispose(){ } /// <summary> ///
将对象池中内定的对象重置并设置为空闲状态 /// </summary> public
void ReturnOne(T obj){ } /// <summary> /// 手动清理对象池 ///
</summary> public void 马努alReleaseObject(){ } ///
<summary> /// 自动清理对象池(对超过 最小体量 的闲暇对象开始展览放飞)
/// </summary> private void AutoReleaseObject(Object obj){ } }
完成的机要代码

 

通过对“对象池”的三个大体会认识识能帮大家更快精晓线程池。

 

线程池ThreadPool类详解

ThreadPool静态类,为应用程序提供3个由系统一管理理的帮助线程池,从而使你能够集中精力于应用程序职分而不是线程管理。各样进程都有贰个线程池,一个Process中只可以有3个实例,它在挨家挨户应用程序域(AppDomain)是共享的。

在里边,线程池将团结的线程划分工小编线程(协助线程)和I/O线程。前者用于实践常常的操作,后者专用于异步IO,比如文件和互联网请求,注意,分类并不表明三种线程自个儿有出入,内部依然是均等的。

金沙注册送58 4public
static class ThreadPool { //
将操作系统句柄绑定到System.Threading.ThreadPool。 public static bool
BindHandle(SafeHandle osHandle); //
检索由ThreadPool.Get马克斯Threads(Int3二,Int32)方法重返的最大线程池线程数和脚下活动线程数之间的差值。
public static void GetAvailableThreads(out int workerThreads , out int
completionPortThreads); //
设置和摸索能够同时处于活动状态的线程池请求的数额。 //
全体大于此数据的乞请将保持排队状态,直到线程池线程变为可用。 public
static bool Set马克斯Threads(int workerThreads, int completionPortThreads);
public static void Get马克斯Threads(out int workerThreads, out int
completionPortThreads); //
设置和检索线程池在新请求预测中维护的空闲线程数。 public static bool
SetMinThreads(int workerThreads, int completionPortThreads); public
static void GetMinThreads(out int workerThreads, out int
completionPortThreads); //
将艺术排入队列以便执行,并钦命包涵该方法所用数据的靶子。此方法在有线程池线程变得可用时实施。
public static bool QueueUserWorkItem(WaitCallback callBack, object
state); // 将重叠的 I/O 操作排队以便执行。假诺成功地将此操作排队到 I/O
达成端口,则为 true;不然为 false。 //
参数overlapped:要排队的System.Threading.NativeOverlapped结构。 public
static bool UnsafeQueueNativeOverlapped(NativeOverlapped* overlapped);
// 将点名的嘱托排队到线程池,但不会将调用堆栈传播到劳重力线程。 public
static bool UnsafeQueueUserWorkItem(WaitCallback callBack, object
state); // 注册二个等待Threading.WaitHandle的寄托,并内定三个 三二十个人有号子整数来表示超时值(以微秒为单位)。 // executeOnlyOnce假如为
true,表示在调用了寄托后,线程将不再在waitObject参数上伺机; // 假若为
false,表示每便达成等待操作后都重置计时器,直到撤除等待。 public static
RegisteredWaitHandle RegisterWaitForSingleObject( WaitHandle waitObject
, WaitOrTimerCallback callBack, object state, Int
milliseconds提姆eOutInterval, bool executeOnlyOnce); public static
RegisteredWaitHandle UnsafeRegisterWaitForSingleObject( WaitHandle
waitObject , WaitOrTimerCallback callBack , object state , int
millisecondsTimeOutInterval , bool executeOnlyOnce); …… } ThreadPool

一)         使用Get马克斯Threads()和Set马克斯Threads()获取和装置最大线程数

可排队到线程池的操作数仅受内部存款和储蓄器的限制;而线程池限制进程中得以同时处于活动状态的线程数(默许境况下,限制每一个CPU 能够使用 2五 个工小编线程和 壹,000 个 I/O 线程(依照机器CPU个数和.net
framework版本的例外,这几个数据恐怕会有浮动)),全体大于此数量的乞请将维持排队情状,直到线程池线程变为可用。

不提出更改线程池中的最大线程数:

a)        
将线程池大小设置得太大,可能会导致更频仍的实践上下文切换及深化能源的争用情状。

线程从素不相识到领会,异步编制程序。b)        
其实FileStream的异步读写,异步发送接受Web请求,System.Threading.Timer定时器,甚至利用delegate的beginInvoke都会暗中同意调用
ThreadPool,也正是说不仅你的代码恐怕利用到线程池,框架之中也大概采纳到。

c)        
3个应用程序池是叁个单身的历程,拥有叁个线程池,应用程序池中得以有八个WebApplication,种种运营在1个独门的AppDomain中,那么些WebApplication公用一个线程池。

 

二)         使用GetMinThreads()和SetMinThreads()获取和设置最小空闲线程数

为防止向线程分配不供给的库房空间,线程池依照一定的岁月距离创立新的空余线程(该区间为半秒)。所以只要最小空闲线程数设置的过小,在短时间内执行大气任务会因为创制新空闲线程的嵌入延迟导致质量瓶颈。最小空闲线程数默许值等于机械上的CPU核数,并且不提出改变最小空闲线程数。

在运转线程池时,线程池具有二个平放延迟,用于启用最小空闲线程数,以增强应用程序的吞吐量。

在线程池运营中,对于推行完职分的线程池线程,不会应声销毁,而是回到到线程池,线程池会维护最小的空闲线程数(固然应用程序全体线程都以悠闲状态),以便队列职分能够及时运转。超越此最小数指标悠闲线程一段时间没事做后会本身醒来终止本人,以节约系统能源。

3)         静态方法GetAvailableThreads()

通过静态方法GetAvailableThreads()返回的线程池线程的最大数目和当下移动数量之间的差值,即获取线程池中当前可用的线程数目

四)         几个参数

方法GetMaxThreads()、Set马克斯Threads()、GetMinThreads()、SetMinThreads()、GetAvailableThreads()钧包括五个参数。参数workerThreads指工小编线程;参数completionPortThreads指异步
I/O 线程。

通过调用 ThreadPool.QueueUserWorkItem 并传递 WaitCallback
委托来使用线程池。也能够经过应用 ThreadPool.RegisterWaitForSingleObject
并传递 WaitHandle(在向其发出非实信号或逾期时,它将掀起对由
WaitOrTimerCallback
委托包装的格局的调用)来将与等待操作相关的工作项排队到线程池中。若要打消等待操作(即不再履行WaitOrTimerCallback委托),可调用RegisterWaitForSingleObject()方法重临的RegisteredWaitHandle的
Unregister 方法。

若果你驾驭调用方的库房与在排队职责执行时期履行的兼具平安全检查查不相干,则还是能使用不安全的办法
ThreadPool.UnsafeQueueUserWorkItem 和
ThreadPool.UnsafeRegisterWaitForSingleObject。QueueUserWorkItem 和
RegisterWaitForSingleObject
都会捕获调用方的堆栈,此堆栈将在线程池线程开头举行职务时合并到线程池线程的仓库中。要是要求开始展览安检,则必须检查整个堆栈,但它还怀有一定的属性费用。使用“不安全的”方法调用并不会提供相对的平安,但它会提供更好的习性。

让叁个线程不分明地守候三个基础对象进入可用状态,那对线程的内存财富来说是一种浪费。ThreadPool.RegisterWaitForSingleObject()为我们提供了一种方法:在2个水源对象变得可用的时候调用1个方式。

运用需注意:

一)         WaitOrTimerCallback委托参数,该信托接受四个名叫timeOut的Boolean参数。假设 WaitHandle 在钦命时间内尚未收取信号(即,超时),则为true,不然为 false。回调方法能够遵照timeOut的值来针对地采纳措施。

二)         名称叫executeOnlyOnce的Boolean参数。传true则表示线程池线程只进行回调方法三遍;若传false则象征内核查象每回收到功率信号,线程池线程都会实施回调方法。等待二个AutoReset伊夫nt对象时,那几个意义尤为有用。

三)         RegisterWaitForSingleObject()方法重临一个RegisteredWaitHandle对象的引用。这些目的标识了线程池正在它上面等待的基石对象。大家得以调用它的Unregister(WaitHandle
waitObject)方法裁撤由RegisterWaitForSingleObject()注册的等候操作(即WaitOrTimerCallback委托不再执行)。Unregister(WaitHandle
waitObject)的WaitHandle参数表示成功裁撤注册的等候操作后线程池会向此指标发出能量信号(set()),若不想接受此布告可以传递null。

         示例:

金沙注册送58 5private
static void Example_RegisterWaitForSingleObject() { //
加endWaitHandle的来由:若是实施过快退出办法会促成有的事物被保释,造成排队的任务不可能实施,原因还在研讨AutoReset伊芙nt endWaitHandle = new AutoReset伊芙nt(false); AutoReset伊芙nt
notificWaitHandle = new AutoReset伊芙nt(false); AutoReset伊芙nt waitHandle
= new AutoReset伊芙nt(false); RegisteredWaitHandle registeredWaitHandle =
ThreadPool.RegisterWaitForSingleObject( waitHandle, (Object state, bool
timedOut) => { if (timedOut)
Console.WriteLine(“RegisterWaitForSingleObject因超时而执行”); else
Console.WriteLine(“RegisterWaitForSingleObject收到WaitHandle复信号”); },
null, TimeSpan.FromSeconds(二), true ); //
撤销等待操作(即不再履行WaitOrTimerCallback委托)
registeredWaitHandle.Unregister(notificWaitHandle); // 通知ThreadPool.RegisterWaitForSingleObject( notificWaitHandle, (Object
state, bool timedOut) => { if (timedOut)
Console.WriteLine(“第伍个RegisterWaitForSingleObject没有调用Unregister()”);
else
Console.WriteLine(“第3个RegisterWaitForSingleObject调用了Unregister()”);
endWaitHandle.Set(); }, null, TimeSpan.FromSeconds(4), true );
endWaitHandle.WaitOne(); } 示例

实行上下文

        
上一小节中提及:线程池最大线程数设置过大大概会导致Windows频仍执行上下文切换,降低程序质量。对于大部分园友不会满足那样的答复,笔者和您同样也喜欢“知其然,再知其所以然”。

.NET中上下文太多,小编最后得出的下结论是:上下文切换中的上下文专指“执行上下文”。

施行上下文包罗:安全上下文、同步上下文(System.Threading.SynchronizationContext)、逻辑调用上下文(System.Runtime.Messaging.CallContext)。即:安全设置(压缩栈、Thread的Principal属性和Windows身份)、宿主设置(System.Threading.HostExcecutingContextManager)以及逻辑调用上下文数据(System.Runtime.Messaging.CallContext的LogicalSetData()和LogicalGetData()方法)。

当三个“时间片”甘休时,假若Windows决定重新调度同二个线程,那么Windows不会举行上下文切换。借使Windows调度了贰个不1的线程,那时Windows执行线程上下文切换。

        
当Windows上下文切换成另3个线程时,CPU将推行贰个不等的线程,而此前线程的代码和数码还在CPU的高速缓存中,(高速缓存使CPU不必常常访问RAM,RAM的速度比CPU高速缓存慢得多),当Windows上下文切换来贰个新线程时,那几个新线程极有不小概率要履行不1的代码并走访不一致的数码,那个代码和数码不在CPU的高速缓存中。由此,CPU必须访问RAM来填充它的高速缓存,以平复相当的慢实汇兑况。可是,在其“时间片”执行完后,2回新的线程上下文切换又生出了。

上下文切换所发生的开支不会换成任何内部存款和储蓄器和性质上的收益。执行上下文所需的年华取决于CPU框架结构和速度(即“时间片”的抽成)。而填充CPU缓存所需的年月取决于系统运作的应用程序、CPU、缓存的高低以及别的各类因素。所以,无法为每叁遍线程上下文切换的时间支付给出多少个规定的值,甚至心慌意乱提交2个推测的值。唯1显著的是,如若要创设高品质的应用程序和组件,就相应尽大概防止线程上下文切换。

而外,执行垃圾回收时,CL本田UR-V必须挂起(暂停)全数线程,遍历它们的栈来查找根以便对堆中的对象进行标记,再一次遍历它们的栈(有的对象在缩减时期发生了运动,所以要立异它们的根),再过来全体线程。所以,收缩线程的数额也会明确升级垃圾回收器的属性。每一回使用一个调节和测试器并碰着二个断点,Windows都会挂起正在调试的应用程序中的全数线程,并在单步执行或运转应用程序时上升全部线程。因而,你用的线程更加多,调节和测试体验也就越差。

Windows实际记录了各种线程被上下文切换来的次数。能够应用像Microsoft
Spy++那样的工具查看这几个数额。这一个工具是Visual
Studio附带的贰个小工具(vs按安装路径\Visual Studio
2012\Common7\Tools),如图

金沙注册送58 6

在《异步编制程序:线程概述及运用》中自身提到了Thread的四个上下文,即:

一)         CurrentContext       
获取线程正在内部实施的近日上下文。首要用于线程内部存储数据。

贰)         ExecutionContext   
获取一个System.Threading.ExecutionContext对象,该对象涵盖关于当前线程的各类上下文的新闻。主要用于线程间数据共享。

内部赢获得的System.Threading.ExecutionContext正是本小节要说的“执行上下文”。

金沙注册送58 7public
sealed class ExecutionContext : IDisposable, ISerializable { public void
Dispose(); public void GetObjectData(SerializationInfo info,
StreamingContext context); //
此措施对于将履行上下文从多个线程传播到另八个线程分外管用。 public
ExecutionContext CreateCopy(); // 从当前线程捕获执行上下文的3个副本。
public static ExecutionContext Capture(); //
在当前线程上的钦命执行上下文中运作有个别方法。 public static void
Run(ExecutionContext executionContext, ContextCallback callback, object
state); // 裁撤执行上下文在异步线程之间的流动。 public static
AsyncFlowControl SuppressFlow(); public static bool IsFlowSuppressed();
// RestoreFlow 打消此前的 SuppressFlow 方法调用的震慑。 // 此措施由
SuppressFlow 方法重临的 AsyncFlowControl 结构的 Undo 方法调用。 //
应使用 Undo 方法(而不是 RestoreFlow 方法)恢复生机执行上下文的流动。 public
static void RestoreFlow(); } View
Code

ExecutionContext
类提供的机能让用户代码能够在用户定义的异步点之间捕获和传导此上下文。公共语言运维时(CLQX56)确定保证在托管进程内运转时定义的异步点之间平等地传输
ExecutionContext。

每当两个线程(早先线程)使用另三个线程(协理线程)执行职务时,CL纳瓦拉会将前者的举行上下文流向(复制到)帮忙线程(注意那些活动流向是单方向的)。这就有限协理了救助线程执行的其余操作使用的是同样的平安设置和宿主设置。还打包票了发轫线程的逻辑调用上下文能够在帮扶线程中接纳。

但实践上下文的复制会招致一定的性质影响。因为实施上下文中蕴涵多量音信,而采访全部这几个信息,再把它们复制到协助线程,要消耗比比皆是年华。倘诺协理线程又利用了越来越多地赞助线程,还非得创立和早先化更多的履行上下文数据结构。

从而,为了进步应用程序质量,大家能够阻止实施上下文的流淌。当然那只有在支援线程不须要可能不访问上下文消息的时候才能开始展览阻挠。

下边给出2个示范为了演示:

壹)         在线程间共享逻辑调用上下文数据(CallContext)。

二)         为了升高品质,阻止\回复执行上下文的流动。

三)         在此时此刻线程上的内定执行上下文中运作某些方法。

金沙注册送58 8private
static void Example_ExecutionContext() {
CallContext.LogicalSetData(“Name”, “小红”);
Console.WriteLine(“主线程中Name为:{0}”,
CallContext.LogicalGetData(“Name”)); // 1)
在线程间共享逻辑调用上下文数据(CallContext)。
Console.WriteLine(“一)在线程间共享逻辑调用上下文数据(CallContext)。”);
ThreadPool.QueueUserWorkItem((Object obj) =>
Console.WriteLine(“ThreadPool线程中Name为:\”{0}\””,
CallContext.LogicalGetData(“Name”))); Thread.Sleep(500);
Console.WriteLine(); // 二) 为了升高品质,打消\复原执行上下文的流淌。
ThreadPool.UnsafeQueueUserWorkItem((Object obj) =>
Console.WriteLine(“ThreadPool线程使用Unsafe异步执行格局来废除执行上下文的流淌。Name为:\”{0}\””
, CallContext.LogicalGetData(“Name”)), null);
Console.WriteLine(“二)为了升高品质,撤除/恢复执行上下文的流动。”);
AsyncFlowControl flowControl = ExecutionContext.SuppressFlow();
ThreadPool.QueueUserWorkItem((Object obj) =>
Console.WriteLine(“(打消ExecutionContext流动)ThreadPool线程中Name为:\”{0}\””,
CallContext.LogicalGetData(“Name”))); Thread.Sleep(500); //
复苏不引进使用ExecutionContext.RestoreFlow() flowControl.Undo();
ThreadPool.QueueUserWorkItem((Object obj) =>
Console.WriteLine(“(苏醒ExecutionContext流动)ThreadPool线程中Name为:\”{0}\””,
CallContext.LogicalGetData(“Name”))); Thread.Sleep(500);
Console.WriteLine(); // 3)
在时下线程上的钦定执行上下文中运转有些方法。(通过得到调用上下文数听他们证明)
Console.WriteLine(“三)在现阶段线程上的钦点执行上下文中运行有些方法。(通过获得调用上下文数据证实)”);
ExecutionContext curExecutionContext = ExecutionContext.Capture();
ExecutionContext.SuppressFlow(); ThreadPool.QueueUserWorkItem( (Object
obj) => { ExecutionContext innerExecutionContext = obj as
ExecutionContext; ExecutionContext.Run(innerExecutionContext, (Object
state) =>
Console.WriteLine(“ThreadPool线程中Name为:\”{0}\””<br> ,
CallContext.LogicalGetData(“Name”)), null); } , curExecutionContext ); }
View Code

结果如图:

金沙注册送58 9

 

 

 注意:

1)        
示例中“在当下线程上的钦定执行上下文中运维有个别方法”:代码中必须使用ExecutionContext.Capture()获取当前推行上下文的多个副本

a)        
若直接利用Thread.CurrentThread.ExecutionContext则会报“不大概采用以下上下文:
跨 AppDomains 封送的上下文、不是通过捕获操作获取的上下文或已作为 Set
调用的参数的上下文。”错误。

b)        
若使用Thread.CurrentThread.ExecutionContext.CreateCopy()会报“只可以复制新近捕获(ExecutionContext.Capture())的上下文”。

二)        
撤销执行上下文流动除了使用ExecutionContext.SuppressFlow()情势外。还足以经过应用ThreadPool的UnsafeQueueUserWorkItem

UnsafeRegisterWaitForSingleObject来施行委托方法。原因是不安全的线程池操作不会传导压缩堆栈。每当压缩堆栈流动时,托管的主脑、同步、区域安装和用户上下文也跟着流动。

 

线程池线程中的万分

线程池线程中未处理的尤其将适可而止进度。以下为此规则的两种例外情状: 

  1. 鉴于调用了 Abort,线程池线程元帅掀起ThreadAbortException。 
    二.
    由夏梅在卸载应用程序域,线程池线程大校引发AppDomainUnloadedException。 
  2. 集体语言运转库或宿主进程将结束线程。

何时不使用线程池线程

未来我们都早已知道线程池为大家提供了有利于的异步API及托管的线程管理。那么是或不是别的时候都应该使用线程池线程呢?当然不是,大家照旧必要“因地制宜”的,在偏下二种情况下,适合于创设并管制本身的线程而不是使用线程池线程:

 

 

  本博文介绍线程池以及其基础对象池,ThreadPool类的采取及注意事项,怎么样排队办事项到线程池,执行上下文及线程上下文字传递递难点…… 

线程池固然为大家提供了异步操作的有益,不过它不辅助对线程池中单个线程的复杂性控制致使我们某些情形下会直接使用Thread。并且它对“等待”操作、“撤废”操作、“一而再”职分等操作比较麻烦,大概驱使你从新造轮子。微软也想到了,所以在.NET4.0的时候进入了“并行职务”并在.NET肆.5中对其展开矫正,想精晓“并行职责”的园友能够先看看《(译)关于Async与Await的FAQ》。

本节到此甘休,感激大家的欣赏。赞的话还请多引进啊 (*^_^*)

 

 

 

 

参考资料:《CL福特Explorer via C#(第三版)》

 

 摘自:

 

异步编制程序:使用线程池管理线程 从此图中大家会发现 .NET 与C#
的各种版本发布都以有三个主旨…

因而CL奥德赛线程池所确立的线程总是私下认可为后台线程,优先级数为ThreadPriority.Normal。

应用程序能够有四个线程,那些线程在蛰伏状态中要求消耗大量岁月来等待事件时有爆发。别的线程只怕进入睡眠情况,并且仅定期被唤起以轮循更改或更新景况音信,然后再一次进入休眠状态。为了简化对这一个线程的管住,.NET框架为各种进度提供了贰个线程池,1个线程池有好七个等待操作景况,当三个等待操作达成时,线程池中的帮忙线程会执行回调函数。线程池中的线程由系统一管理理,程序员不必要费劲于线程管理,能够集中精力处理应用程序职责。通过基础类库中的ThreadPool类提供二个线程池,该线程池可用以发送工作现,处理异步I/O,代表任何线程等待及处理计时器.ThreadPool类的拥有办法都以静态方法.ThreadPool自个儿也是一个静态类.
作者们来探视她的定义和某些常用的方法:
 public
static class ThreadPool
{
 [SecuritySafeCritical]
        public static void
GetAvailableThreads(out int workerThreads, out int
completionPortThreads);
        [SecuritySafeCritical]
        public static void
GetMaxThreads(out int workerThreads, out int
completionPortThreads);
        [SecuritySafeCritical]
        public static void
GetMinThreads(out int workerThreads, out int
completionPortThreads);
        [SecuritySafeCritical]
        public static bool
QueueUserWorkItem(WaitCallback callBack);
        [SecuritySafeCritical]
        public static bool
QueueUserWorkItem(WaitCallback callBack, object state);
}
GetAvailableThreads那几个办法重临的最大线程池线程数和眼下活动线程数之间的差值。
参数 workerThreads: 可用协理线程的数目。completionPortThreads: 可用异步
I/O 线程的数码。
GetMaxThreads方法取稳妥前由线程池维护的帮扶线程的最大数目.参数
workerThreads: 线程池中补助线程的最大数额。completionPortThreads:
当前由线程池维护的空余异步 I/O 线程的最大数据。
GetMinThreads方法赢妥帖前由线程池维护的空闲帮助线程的矮小数目.参数
workerThreads:
当前由线程池维护的悠闲帮衬线程的小不点儿数目.completionPortThreads:
当前由线程池维护的闲暇异步 I/O 线程的微乎其微数目。
QueueUserWorkItem方法将艺术排入队列以便执行。参数callBack,
表示要推行的方法.state:包罗方法所用数据的靶子。
上边看个例子:

  在面向对象编制程序中,创造和销毁对象是很费时间的,因为创造一个目的要获取内部存储器能源依然别的越多财富,所以抓实服务程序作用的一个手腕正是尽大概收缩成立和销毁对象的次数,尤其是有的很耗财富的靶子创设和销毁。怎么样使用已有指标来服务就是三个亟待解决的关键难点,其实那正是壹对”池化能源”技术发生的来由。比如我们所熟知的数据库连接池就是依照那一思虑而发生的,本文将介绍的线程池技术1样符合那一思维。

CL奥迪Q5线程池分为劳动力线程(workerThreads)I/O线程(completionPortThreads)两种:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading;
 6 
 7 namespace ConsoleApplication6
 8 {
 9     class Program
10     {
11         static void Main(string[] args)
12         {
13             Console.WriteLine("主线程进行异步条用");
14 
15             AutoResetEvent asyncOpIsDone = new AutoResetEvent(false);
16             ThreadPool.QueueUserWorkItem(new WaitCallback((x) =>
17             {
18 
19                 Thread.Sleep(1000);
20                 Console.WriteLine("工作任务");
21 
22             }));
23             string s="我的参数";
24             ThreadPool.QueueUserWorkItem(new WaitCallback((x) =>
25             {
26                
27                 Thread.Sleep(2000);
28                 Console.WriteLine("工作任务1");
29                 Console.WriteLine(x);
30                
31             }), s);
32             ThreadPool.QueueUserWorkItem(new WaitCallback(MyAsyncOperation), asyncOpIsDone);
33             Console.WriteLine("主线程执行其他");
34             Console.WriteLine("主线程等待任务处理结束");
35             asyncOpIsDone.WaitOne();
36         }
37         static void MyAsyncOperation(Object state)
38         {
39            
40             Thread.Sleep(5000);
41             Console.WriteLine("工作任务2");
42             ((AutoResetEvent)state).Set();
43         }
44     }
45 }

  • 劳力线程是重大用作管理CLHummerH贰内部对象的运维,平常用于总括密集的职分。
  • I/O(Input/Output)线程最首要用来与外表系统互相消息,如输入输出,CPU仅需在义务早先的时候,将任务的参数字传送递给设备,然后运维硬件设备即可。等任务成功的时候,CPU收到三个布告,一般的话是四个硬件的刹车数字信号,此时CPU继续后继的拍卖工作。在处理进度中,CPU是不要完全参加处理进程的,假如正在周转的线程不交出CPU的控制权,那么线程也不得不处于等候状态,即便操作系统将近年来的CPU调度给此外线程,此时线程所占据的上空照旧被占用,而并从未CPU处理这么些线程,大概出现线程能源浪费的题材。即使那是一个网络服务程序,每1个互连网连接都应用多少个线程管理,只怕出现大批量线程都在守候互连网通讯,随着互联网连接的接踵而至 蜂拥而至加码,处于等候境况的线程将会很开销尽全部的内部存储器财富。能够思虑使用线程池化解那么些难点。

 

  10二线程是何许?组成?特点?

  线程池的最大值一般暗中同意为1000、3000。当不止此数量的伸手时,将保持排队状态,直到线程池里有线程可用。

 运维的结果为

  线程池是一种拾贰线程处理格局,处理进度团长任务添加到行列,然后在创造线程后自行运行那一个职责。线程池中的线程由系统一管理理,程序员不须求费劲于线程管理,能够集中精力处理应用程序职分。

  使用CL凯雷德线程池的劳重力线程壹般有二种办法:

金沙注册送58 10

  组成:服务器程序利用线程技术响应客户请求已经无独有偶,大概你认为那样做功用已经很高,但您有未有想过优化一下采纳线程的点子。该小说将向你介绍服务器程序怎么着利用线程池来优化品质并提供1个简短的线程池完毕。

  • 通过ThreadPool.QueueUserWorkItem()方法;
  • 通过委托;

此地有个类为AutoReset伊芙nt,他的功力是打招呼正在等候的线程已发出事件。他是从伊芙ntWaitHandle继承而来的!例子中分别用了二种分歧的主意调用,第两种是可以传递参数的!工作线程一就传递了”作者的参数”字符串!工作线程2周转完了会通报等待的线程已发出事件.那里AutoResetEvent起头化的时候首先将确定性信号设成false,工作线程二万壹调用成功,将被设成true. asyncOpIsDone.WaitOne()阻塞当前线程,直到收到时域信号!

  一、线程池管理器(ThreadPoolManager):用于创建并管理线程池

  要留心,不论是经过ThreadPool.QueueUserWorkItem()照旧委托,调用的都是线程池里的线程。

再看上边包车型地铁例证

  二、工作线程(WorkThread): 线程池中线程

经过以下三个主意可以读取和设置CL奥迪Q7线程池湖南中华工程集团作者线程与I/O线程的最大线程数。

 

  叁、职责接口(Task):各个职分必须完成的接口,以供工作线程调度职分的实施。

  1. ThreadPool.GetMax(out in workerThreads,out int
    completionPortThreads);
  2. ThreadPool.SetMax(int workerThreads,int completionPortThreads);

 

  4、职务队列:用于存放未有拍卖的天职。提供一种缓冲机制。

  若想测试线程池中有个别许线程正在投入使用,可以透过ThreadPool.GetAvailableThreads(out
in workThreads,out int conoletionPortThreads)方法。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading;
 6 
 7 namespace ConsoleApplication7
 8 {
 9     class Program
10     {
11         static void Main(string[] args)
12         {
13             Console.WriteLine("\n当前线程的HashCode:{0}", Thread.CurrentThread.GetHashCode().ToString());
14             Console.WriteLine("当前应用域的名字为:{0}", AppDomain.CurrentDomain.FriendlyName);
15             int workerThreads;
16             int completionPortThreads;
17 
18             AutoResetEvent asyncOpIsDone = new AutoResetEvent(false);//信号初始为空
19             AutoResetEvent asyncOpIsDone2 = new AutoResetEvent(false);
20             ThreadPool.QueueUserWorkItem(new WaitCallback(MyWork), asyncOpIsDone);
21             ThreadPool.QueueUserWorkItem(new WaitCallback(MyWork1), asyncOpIsDone2);
22             ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
23             Console.WriteLine("得当前由线程池维护的辅助线程的最大数目:{0}", workerThreads);
24             ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads);
25             Console.WriteLine("得当前由线程池维护的空闲辅助线程的最小数目:{0}", workerThreads);
26             /*WaitHandle[] waithandles = new WaitHandle[2];
27             waithandles[0] = asyncOpIsDone;
28             waithandles[1] = asyncOpIsDone2;
29             WaitHandle.WaitAll(waithandles);  */     
30             //或者可以这样
31             asyncOpIsDone.WaitOne();
32             Console.WriteLine("MyWork结束");
33             asyncOpIsDone2.WaitOne();
34             Console.WriteLine("MyWork1结束");
35         }
36         static void MyWork(Object state)
37         {
38             Console.WriteLine("\n当前线程的HashCode:{0}", Thread.CurrentThread.GetHashCode().ToString());
39             Console.WriteLine("当前应用域的名字为:{0}", AppDomain.CurrentDomain.FriendlyName);
40             Thread.Sleep(2000);
41             ((AutoResetEvent)state).Set();//表示工作已经完成
42         }
43         static void MyWork1(Object state)
44         {
45             Console.WriteLine("\n当前线程的HashCode:{0}", Thread.CurrentThread.GetHashCode().ToString());
46             Console.WriteLine("当前应用域的名字为:{0}", AppDomain.CurrentDomain.FriendlyName);
47             Thread.Sleep(1000);
48             ((AutoResetEvent)state).Set();//表示工作已经完成
49         }
50 
51     }
52 }

 

方法 说明
GetAvailableThreads 剩余空闲线程数
GetMaxThreads 最多可用线程数,所有大于此数目的请求将保持排队状态,直到线程池线程变为可用
GetMinThreads 检索线程池在新请求预测中维护的空闲线程数
QueueUserWorkItem 启动线程池里得一个线程(队列的方式,如线程池暂时没空闲线程,则进入队列排队)
SetMaxThreads 设置线程池中的最大线程数
SetMinThreads 设置线程池最少需要保留的线程数

 

  特点:

我们能够使用线程池来消除地方的大部标题,跟使用单个线程相比,使用线程池有如下优点:

运行结果为

  • 一个历程有且只有二个线程池。
  • 线程池线程皆以后台线程(即不会阻碍进度的停下)
  • 各种线程都使用暗中认可堆栈大小,以暗许的先行级运营,并处在二十四线程单元中。抢先最大值的其他线程必要排队,但它们要等到其余线程完毕后才开动。
  • 在CL汉兰达 二.0 SP1在此以前的本子中,线程池中 暗中认可最大的线程数量 = 处理器数 *
    二5, CLOdyssey 2.0 SP一之后就成为了 默许最大线程数量 = 处理器数 *
    250,线程上限能够改变,通过使用ThreadPool.Get马克斯+Threads和ThreadPool.Set马克斯Threads方法,可以得到和设置线程池的最大线程数。
  • 暗中认可情状下,每个处理器维持二个悠闲线程,即私下认可最小线程数 =
    处理器数。
  • 当进程运行时,线程池并不会自行创建。当第二次将回调方法排入队列(比如调用ThreadPool.QueueUserWorkItem方法)时才会成立线程池。
  • 在对2个工作项进行排队之后将无法裁撤它。
  • 线程池中线程在成功任务后并不会自动销毁,它会以挂起的场所重返线程池,若是应用程序再度向线程池发出请求,那么这些挂起的线程将激活并履行义务,而不会创建新线程,那将节约了诸多开发。唯有线程达到最大线程数量,系统才会以自然的算法销毁回收线程。

一、收缩应用程序的响应时间。因为在线程池中无线程的线程处于等候分配任务状态(只要未有超越线程池的最大上限),无需创造线程。

 


二、不必管理和保卫安全生活周期短暂的线程,不用在创制时为其分配能源,在其实施完任务之后自由能源。

金沙注册送58 11

  怎么时候使用线程池?**  **

三、线程池会依照方今系统性子对池内的线程举办优化处理。

本例中得以详细看AutoRest伊夫nt的用法MyWork①实际上先停止的,可是asyncOpIsDone需求等MyWork的确定性信号!所以先输出了MyWork停止.那里还有叁个事物本身想说的正是WaitHandle,上边的例子已经交付了她的用法!他是AutoRsetEvent的基类.

  一、供给大批量的线程来形成职责,且完成职责的时刻比较短。
WEB服务器达成网页请求那样的天职,使用线程池技术是尤其方便的。因为单个职分小,而职务数量巨大,你能够想象三个热点网址的点击次数。
但对于长日子的天职,比如一个Telnet连接请求,线程池的长处就不强烈了。因为Telnet会话时间比线程的成立时间大多了。

简而言之使用线程池的效劳正是压缩成立和销毁线程的种类开发。在.NET中有一个线程的类ThreadPool,它提供了线程池的田管。

还有ThreadPool有2个函数RegisterWaitForSingleObject那些函数依然满有意思的!小编那边就不再给出例子了!

  二、对性能须求苛刻的利用,比如须要服务器快速响应客户请求。

ThreadPool是一个静态类,它并未构造函数,对外提供的函数也整个是静态的。在那之中有一个QueueUserWorkItem方法,它有两种重载情势,如下:

好了,明日就到那了!

  3、接受突发性的大度伸手,但未必使服务器由此产生多量线程的应用。突发性大量客户请求,在并未线程池意况下,将生出大量线程,纵然理论上绝超过五成操作系统线程数目最大值不是题材,长期内发生大批量线程也许使内部存款和储蓄器到达极限,并冒出”OutOfMemory”的谬误。

public static bool QueueUserWorkItem(WaitCallback
callBack):将艺术排入队列以便执行。此措施在有线程池线程变得可用时实施。

    

public static bool QueueUserWorkItem(WaitCallback
callBack,Object
state):将艺术排入队列以便执行,并点名包蕴该方法所用数据的指标。此办法在有线程池线程变得可用时举办。

  如哪天候不合乎使用线程池?

QueueUserWorkItem方法中选拔的的WaitCallback参数表示2个delegate,它的评释如下:

  

public delegate void WaitCallback(Object
state)

  ●若是须要使1个职责具有一定优先级

若是急需传递职务音信能够动用WaitCallback中的state参数,类似于ParameterizedThreadStart委托。

  ●假诺全部希望会长期运作(并由此阻塞其余职务)的天职

上面是二个ThreadPool的事例,代码如下:

  ●假若急需将线程放置到单线程单元中(线程池中的线程平均高度居二十10贰线程单元中)

金沙注册送58 12金沙注册送58 13

  ●假如急需永久标识来标识和决定线程,比如想行使专用线程来终止该线程,将其挂起或按名称发现它。

using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp1
{
    class ThreadPoolDemo
    {
        public ThreadPoolDemo()
        {
        }

        public void Work()
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(CountProcess));
            ThreadPool.QueueUserWorkItem(new WaitCallback(GetEnvironmentVariables));
        }
        /// <summary>  
        /// 统计当前正在运行的系统进程信息  
        /// </summary>  
        /// <param name="state"></param>  
        private void CountProcess(object state)
        {
            Process[] processes = Process.GetProcesses();
            foreach (Process p in processes)
            {
                try
                {
                    Console.WriteLine("进程信息:Id:{0},ProcessName:{1},StartTime:{2}", p.Id, p.ProcessName, p.StartTime);
                }
                catch (Win32Exception e)
                {
                    Console.WriteLine("ProcessName:{0}", p.ProcessName);
                }
                finally
                {
                }
            }
            Console.WriteLine("获取进程信息完毕。");
        }
        /// <summary>  
        /// 获取当前机器系统变量设置  
        /// </summary>  
        /// <param name="state"></param>  
        public void GetEnvironmentVariables(object state)
        {
            IDictionary list = System.Environment.GetEnvironmentVariables();
            foreach (DictionaryEntry item in list)
            {
                Console.WriteLine("系统变量信息:key={0},value={1}", item.Key, item.Value);
            }
            Console.WriteLine("获取系统变量信息完毕。");
        }
    }
}

ThreadPoolDemo

  线程池常用艺术介绍?

金沙注册送58 14金沙注册送58 15

  

using System;
using System.Threading;

namespace ConsoleApp1
{

    class Program
    {
        static void Main(string[] args)
        {
            ThreadPoolDemo tpd1 = new ThreadPoolDemo();
            tpd1.Work();
            Thread.Sleep(5000);
            Console.WriteLine("OK");
            Console.ReadLine();
        }
    }
}

  一、Get马克斯Threads()    :
 获取能够同时处于活动状态的线程池请求的最大数额。全数大于此数据的央求将保持排队状态,直到线程池线程变为可用。

Program

    •   函数原型:public static void Get马克斯Threads (out int
      workerThreads,out int completionPortThreads)

 

                  参数一:workerThreads
:线程池中帮助线程的最大数额。 
                  参数二:completionPortThreads :线程池中异步 I/O
线程的最大数额。 

运用ThreadPool调用工作线程和IO线程的范例

 

金沙注册送58 16金沙注册送58 17

  2、GetMinThreads()    获取线程池维护的微乎其微空闲线程数。        

using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Threading;

namespace ConsoleApp1
{

    class Program
    {
        static void Main(string[] args)
        {
            // 设置线程池中处于活动的线程的最大数目
            // 设置线程池中工作者线程数量为1000,I/O线程数量为1000
            ThreadPool.SetMaxThreads(1000, 1000);
            Console.WriteLine("Main Thread: queue an asynchronous method");
            PrintMessage("Main Thread Start");

            // 把工作项添加到队列中,此时线程池会用工作者线程去执行回调方法            
            ThreadPool.QueueUserWorkItem(asyncMethod);
            asyncWriteFile();
            Console.Read();
        }

        // 方法必须匹配WaitCallback委托
        private static void asyncMethod(object state)
        {
            Thread.Sleep(1000);
            PrintMessage("Asynchoronous Method");
            Console.WriteLine("Asynchoronous thread has worked ");
        }


        #region 异步读取文件模块
        private static void asyncReadFile()
        {
            byte[] byteData = new byte[1024];
            FileStream stream = new FileStream(@"D:\123.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 1024, true);
            //把FileStream对象,byte[]对象,长度等有关数据绑定到FileDate对象中,以附带属性方式送到回调函数
            Hashtable ht = new Hashtable();
            ht.Add("Length", (int)stream.Length);
            ht.Add("Stream", stream);
            ht.Add("ByteData", byteData);

            //启动异步读取,倒数第二个参数是指定回调函数,倒数第一个参数是传入回调函数中的参数
            stream.BeginRead(byteData, 0, (int)ht["Length"], new AsyncCallback(Completed), ht);
            PrintMessage("asyncReadFile Method");
        }

        //实际参数就是回调函数
        static void Completed(IAsyncResult result)
        {
            Thread.Sleep(2000);
            PrintMessage("asyncReadFile Completed Method");
            //参数result实际上就是Hashtable对象,以FileStream.EndRead完成异步读取
            Hashtable ht = (Hashtable)result.AsyncState;
            FileStream stream = (FileStream)ht["Stream"];
            int length = stream.EndRead(result);
            stream.Close();
            string str = Encoding.UTF8.GetString(ht["ByteData"] as byte[]);
            Console.WriteLine(str);
            stream.Close();
        }
        #endregion

        #region 异步写入文件模块
        //异步写入模块
        private static void asyncWriteFile()
        {
            //文件名 文件创建方式 文件权限 文件进程共享 缓冲区大小为1024 是否启动异步I/O线程为true
            FileStream stream = new FileStream(@"D:\123.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 1024, true);
            //这里要注意,如果写入的字符串很小,则.Net会使用辅助线程写,因为这样比较快
            byte[] bytes = Encoding.UTF8.GetBytes("你在他乡还好吗?");
            //异步写入开始,倒数第二个参数指定回调函数,最后一个参数将自身传到回调函数里,用于结束异步线程
            stream.BeginWrite(bytes, 0, (int)bytes.Length, new AsyncCallback(Callback), stream);
            PrintMessage("AsyncWriteFile Method");
        }

        static void Callback(IAsyncResult result)
        {
            //显示线程池现状
            Thread.Sleep(2000);
            PrintMessage("AsyncWriteFile Callback Method");
            //通过result.AsyncState再强制转换为FileStream就能够获取FileStream对象,用于结束异步写入
            FileStream stream = (FileStream)result.AsyncState;
            stream.EndWrite(result);
            stream.Flush();
            stream.Close();
            asyncReadFile();
        }
        #endregion

        // 打印线程池信息
        private static void PrintMessage(String data)
        {
            int workthreadnumber;
            int iothreadnumber;

            // 获得线程池中可用的线程,把获得的可用工作者线程数量赋给workthreadnumber变量
            // 获得的可用I/O线程数量给iothreadnumber变量
            ThreadPool.GetAvailableThreads(out workthreadnumber, out iothreadnumber);

            Console.WriteLine("{0}\n CurrentThreadId is {1}\n CurrentThread is background :{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is: {4}\n",
                data,
                Thread.CurrentThread.ManagedThreadId,
                Thread.CurrentThread.IsBackground.ToString(),
                workthreadnumber.ToString(),
                iothreadnumber.ToString());
        }
    }
}
  • 函数原型:public static void GetMinThreads (out int
    workerThreads,out int completionPortThreads)
    参数1:workerThreads:当前由线程池维护的悠闲协理线程的纤维数目。 
    参数二:completionPortThreads:当前由线程池维护的空闲异步 I/O
    线程的微乎其微数目。 

Program

 

 

  叁、Set马克斯Threads()  
 设置能够而且处于活动状态的线程池的最大请求数目(不考虑总计机处理器的数量)

线程池中放入异步操作

    • 函数原型:public static bool SetMinThreads (int
      workerThreads,intcompletionPortThreads)

金沙注册送58 18金沙注册送58 19

             
 参数一:workerThreads::要由线程池维护的新的微小空闲帮忙线程数。 
             
 参数2:completionPortThreads::要由线程池维护的新的矮小空闲异步 I/O
线程数。 
               重回值:假使改动成功,则为 true;不然为 false。 

using System;
using System.Threading;

namespace ConsoleApp1
{

    class Program
    {
        private static void AsyncOperation(object state)
        {
            Console.WriteLine("Operation state: {0}", state ?? "(null)");
            Console.WriteLine("Worker thread id: {0}", Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(TimeSpan.FromSeconds(2));
        }

        static void Main(string[] args)
        {
            const int x = 1;
            const int y = 2;
            const string lambdaState = "lambda state 2";

            ThreadPool.QueueUserWorkItem(AsyncOperation);
            Thread.Sleep(TimeSpan.FromSeconds(1));

            ThreadPool.QueueUserWorkItem(AsyncOperation, "async state");
            Thread.Sleep(TimeSpan.FromSeconds(1));

            ThreadPool.QueueUserWorkItem(state => {
                Console.WriteLine("Operation state: {0}", state);
                Console.WriteLine("Worker thread id: {0}", Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(TimeSpan.FromSeconds(2));
            }, "lambda state");

            ThreadPool.QueueUserWorkItem(_ =>
            {
                Console.WriteLine("Operation state: {0}, {1}", x + y, lambdaState);
                Console.WriteLine("Worker thread id: {0}", Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(TimeSpan.FromSeconds(2));
            }, "lambda state");

            Thread.Sleep(TimeSpan.FromSeconds(2));
        }
    }
}

 

Program

金沙注册送58 ,  4、SetMinThreads()    
设置线程池在新请求预测中爱抚的空闲线程数(不思量计算机处理器的数据)

 

    • 函数原型:public static bool SetMinThreads (int
      workerThreads,intcompletionPortThreads)

线程池同步操作

             
 参数一:workerThreads:要由线程池维护的新的微小空闲协理线程数。 
             
 参数贰:completionPortThreads:要由线程池维护的新的矮小空闲异步 I/O
线程数。 
               重临值:借使改变成功,则为 true;不然为 false。 

金沙注册送58 20金沙注册送58 21

  

using System;
using System.Threading;

namespace ConsoleApp1
{
    class ThreadPoolDemo
    {
        static object lockobj = new object();
        static int Count = 0;
        ManualResetEvent manualEvent;
        public ThreadPoolDemo(ManualResetEvent manualEvent)
        {
            this.manualEvent = manualEvent;
        }
        public void DisplayNumber(object a)
        {

            lock (lockobj)
            {
                Count++;
                Console.WriteLine("当前运算结果:{0},Count={1},当前子线程id:{2} 的状态:{3}", a, Count, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ThreadState);
            }
            //Console.WriteLine("当前运算结果:{0}", a);
            //Console.WriteLine("当前运算结果:{0},当前子线程id:{1} 的状态:{2}", a,Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ThreadState);
            //这里是方法执行时间的模拟,如果注释该行代码,就能看出线程池的功能了
            Thread.Sleep(2000);
            //Console.WriteLine("当前运算结果:{0},Count={1},当前子线程id:{2} 的状态:{3}", a, Count, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ThreadState);
            //这里是释放共享锁,让其他线程进入
            manualEvent.Set();


        }
    }
}

  5、GetAvailableThreads()    获取由 Get马克斯Threads
重临的线程池线程的最大数额和当前活动数量之间的差值。    

ThreadPoolDemo

    • 函数原型:public static void GetAvailableThreads (out int
      workerThreads,out int completionPortThreads)

金沙注册送58 22金沙注册送58 23

                参数一:workerThreads:可用帮忙线程的多少。 
                参数二:completionPortThreads:可用异步 I/O 线程的数目。 

using System;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp1
{

    class Program
    {
        //设定任务数量 
        static int count = 10;
        static void Main(string[] args)
        {
            //让线程池执行5个任务所以也为每个任务加上这个对象保持同步
            ManualResetEvent[] events = new ManualResetEvent[count];
            Console.WriteLine("当前主线程id:{0}", Thread.CurrentThread.ManagedThreadId);

            Stopwatch sw = new Stopwatch();
            sw.Start();
            NoThreadPool(count);
            sw.Stop();
            Console.WriteLine("Execution time using threads: {0}", sw.ElapsedMilliseconds);


            sw.Reset();
            sw.Start();
            //循环每个任务
            for (int i = 0; i < count; i++)
            {
                //实例化同步工具
                events[i] = new ManualResetEvent(false);
                //Test在这里就是任务类,将同步工具的引用传入能保证共享区内每次只有一个线程进入
                ThreadPoolDemo tst = new ThreadPoolDemo(events[i]);
                //Thread.Sleep(200);
                //将任务放入线程池中,让线程池中的线程执行该任务                 
                ThreadPool.QueueUserWorkItem(tst.DisplayNumber, i);
            }
            //注意这里,设定WaitAll是为了阻塞调用线程(主线程),让其余线程先执行完毕,
            //其中每个任务完成后调用其set()方法(收到信号),当所有
            //的任务都收到信号后,执行完毕,将控制权再次交回调用线程(这里的主线程)
            ManualResetEvent.WaitAll(events);
            sw.Stop();
            Console.WriteLine("Execution time using threads: {0}", sw.ElapsedMilliseconds);
            //Console.WriteLine("所有任务做完!");
            Console.ReadKey();
        }

        static void NoThreadPool(int count)
        {
            for (int i = 0; i < count; i++)
            {
                Thread.Sleep(2000);
                Console.WriteLine("当前运算结果:{0},Count={1},当前子线程id:{2} 的状态:{3}", i, i + 1, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ThreadState);
            }
        }

    }
}

 

Program

  陆、QueueUserWorkItem()  
 将艺术排入队列以便执行。此格局在有线程池线程变得可用时进行。 

 

    • 重载方法一:public static bool QueueUserWorkItem (WaitCallback
      callBack)

线程池中的撤消操作

                重返值:借使将艺术成功排入队列,则为 true;不然为
false。 

金沙注册送58 24金沙注册送58 25

    • 重载方法二:public static bool QueueUserWorkItem (WaitCallback
      callBack,Object state)
using System;
using System.Threading;

namespace ConsoleApp1
{

    class Program
    {
        static void Main(string[] args)
        {
            ThreadPool.SetMaxThreads(1000, 1000);
            Console.WriteLine("Main thread run");
            PrintMessage("Start");
            Run();
            Console.ReadKey();
        }

        private static void Run()
        {
            CancellationTokenSource cts = new CancellationTokenSource();

            // 这里用Lambda表达式的方式和使用委托的效果一样的,只是用了Lambda后可以少定义一个方法。
            // 这在这里就是让大家明白怎么lambda表达式如何由委托转变的
            ////ThreadPool.QueueUserWorkItem(o => Count(cts.Token, 1000));
            ThreadPool.QueueUserWorkItem(callback, cts.Token);

            Console.WriteLine("Press Enter key to cancel the operation\n");
            Console.ReadLine();

            // 传达取消请求            
            cts.Cancel();
            Console.ReadLine();
        }

        private static void callback(object state)
        {
            Thread.Sleep(1000);
            PrintMessage("Asynchoronous Method Start");
            CancellationToken token = (CancellationToken)state;
            Count(token, 1000);
        }

        // 执行的操作,当受到取消请求时停止数数
        private static void Count(CancellationToken token, int countto)
        {
            for (int i = 0; i < countto; i++)
            {
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine("Count is canceled");
                    break;
                }

                Console.WriteLine(i);
                Thread.Sleep(300);
            }

            Console.WriteLine("Cout has done");
        }

        // 打印线程池信息
        private static void PrintMessage(String data)
        {
            int workthreadnumber;
            int iothreadnumber;

            // 获得线程池中可用的线程,把获得的可用工作者线程数量赋给workthreadnumber变量
            // 获得的可用I/O线程数量给iothreadnumber变量
            ThreadPool.GetAvailableThreads(out workthreadnumber, out iothreadnumber);

            Console.WriteLine("{0}\n CurrentThreadId is {1}\n CurrentThread is background :{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is: {4}\n",
                data,
                Thread.CurrentThread.ManagedThreadId,
                Thread.CurrentThread.IsBackground.ToString(),
                workthreadnumber.ToString(),
                iothreadnumber.ToString());
        }
    }
}

               参数二:state :包括方法所用数据的对象。 
               重返值:假如将艺术成功排入队列,则为 true;不然为
false。 
      备注:WaitCallback
回调方法必须与System.Threading.WaitCallback委托项目相匹配。

Program

         WaitCallback函数原型:public delegate void
WaitCallback(Object state);调用QueueUserWorkItem可以透过Object来向职务进度传递参数。假若职分进度要求多少个参数,能够定义包罗那几个数据的类,并将类的实例强制转换为Object数据类型。

 

 

Thread与ThreadPool的一天性质比较

  七、UnsafeQueueUserWorkItem()    非安全性注册3个等候 WaitHandle
的委托(将艺术排入队列以便执行)。

金沙注册送58 26金沙注册送58 27

    • 函数原型:public static bool UnsafeQueueUserWorkItem
      (WaitCallback callBack,Object state)     
      //不将调用堆栈传播到帮助线程上。这允许代码失去调用堆栈,从而进步了它的长治特权。
    • 备考:使用
      UnsafeQueueUserWorkItem
      可能会无形中中开拓1个安全漏洞。代码访问安全性的权杖检查根据所有调用方对堆栈的权力进行。要是使用
      UnsafeQueueUserWorkItem
      将工作排在有个别线程池线程上,则该线程池线程的堆栈将不会拥有实际调用方的背景。恶意代码可能会接纳这点避开权限检查。
using System;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            const int numberOfOperations = 300;
            var sw = new Stopwatch();
            sw.Start();
            UseThreads(numberOfOperations);
            sw.Stop();
            Console.WriteLine("Execution time using threads: {0}", sw.ElapsedMilliseconds);

            sw.Reset();
            sw.Start();
            UseThreadPool(numberOfOperations);
            sw.Stop();
            Console.WriteLine("Execution time using threadPool: {0}", sw.ElapsedMilliseconds);
        }

        static void UseThreads(int numberOfOperations)
        {
            using (var countdown = new CountdownEvent(numberOfOperations))
            {
                Console.WriteLine("Scheduling work by creating threads");
                for (int i = 0; i < numberOfOperations; i++)
                {
                    var thread = new Thread(() => {
                        Console.Write("{0},", Thread.CurrentThread.ManagedThreadId);
                        Thread.Sleep(TimeSpan.FromSeconds(0.1));
                        countdown.Signal();
                    });
                    thread.Start();
                }
                countdown.Wait();
                Console.WriteLine();
            }
        }

        static void UseThreadPool(int numberOfOperations)
        {
            using (var countdown = new CountdownEvent(numberOfOperations))
            {
                Console.WriteLine("Starting work on a threadpool");
                for (int i = 0; i < numberOfOperations; i++)
                {
                    ThreadPool.QueueUserWorkItem(_ => {
                        Console.Write("{0},", Thread.CurrentThread.ManagedThreadId);
                        Thread.Sleep(TimeSpan.FromSeconds(0.1));
                        countdown.Signal();
                    });
                }
                countdown.Wait();
                Console.WriteLine();
            }
        }
    }
}

 

Program

  八、RegisterWaitForSingleObject()    
将点名的信托排队到线程池。当发生以下处境之一时,支持线程将举行委托。

 

  九、UnsafeRegisterWaitForSingleObject()  
非安全性将点名的信托排队到线程池。

 


 

  线程池示例?

 

  大家先来看二个简易的线程实例:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Begin in Main");
            Thread t = new Thread(ThreadInvoke);
            t.IsBackground = true;
            t.Start();

            //将当前线程挂起200毫秒
            Thread.Sleep(200);
            Console.WriteLine("End in Main");
            Console.ReadKey();
        }

        static void ThreadInvoke(object obj)
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Execute in ThreadInvoke");
                //每隔100毫秒,循环一次
                Thread.Sleep(100);
            }
        }
    }
}

金沙注册送58 28

 

“End in Main”并不曾在ThreadInvoke()方法中存有代码执行完事后才输出。

总而言之Main方法和ThreadInvoke是并行执行的

 

  使用线程池改造下边包车型客车演示:

    上边介绍了只是三个最简便的有关线程线程的例子,但在实际上开发中动用的线程往往是大方的和更为复杂的,那时,每趟都创制线程、运维线程。从性质上来讲,那样做并不美貌(因为每使用多个线程就要成立贰个,须求占用系统开发);从操作上来讲,每一回都要运行,比较费劲。为此引入的线程池的定义。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Begin in Main");
            ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadInvoke));
            Console.WriteLine("End in Main");
            //将当前线程挂起200毫秒
            Thread.Sleep(3000);

            Console.ReadKey();
        }

        static void ThreadInvoke(object obj)
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Execute in ThreadInvoke");
                //每隔100毫秒,循环一次
                Thread.Sleep(100);
            }
        }
    }
}

 

Thread.Sleep(三千)那句话是必须的因为当Main方法结束后,.Net环境会自行终止销毁线程池,为了确定保障达成线程池里的义务,所以主线程需求等待一段时间。 

由输出结果能够,Main方法和ThreadInvoke方法是并行执行的。

 

相关文章

网站地图xml地图