《CLR via C#》读书笔记-.NET多线程(三)

CLR线程池基础
1、每一个CLR有一个线程池
2、应用程序申请线程池的流程。线程池的最开始是没有线程的。线程池会有一个请求队列。当应用程序请求一个线程的时候,CLR会调用某个方法,将请求放入线程池的请求队列中。然后线程池会创建新的线程后,将应用程序请求dispatch至新建的线程。若线程完成应用的请求后,线程会返还至线程池中,等待新的任务请求。若一直没有新的请求,则线程会自动终结。另外,线程池中的线程并不是为每一个请求创建一个新的线程,其创建线程的逻辑应该根据任务请求数量,以及根据一个timeout值进行判断的。
3、线程池中线程的分类。线程池中默认分为工作者线程和I/O线程。其中工作者线程是平时用的最多的。例如:在往多个数据库表从插入数据,数据多、量大、耗时长,这时线程是一个往数据库服务器上硬盘写入数据的I/O操作。I/O线程是一个通知线程,通知你的代码一个异步的I/O操作完成了。
多线程做的事情有很多种:读取寄存器中的数据进行异步处理、读取内存的数据进行异步处理、读取本机硬盘及其他服务器上的硬盘进行的异步处理。读取硬盘相关的异步处理就是一个I/O操作。
ThreadPool
ThreadPool类是CLR提供的一个线程池,本类没有属性,只有方法
在使用ThreadPool中最常用的方法及相关方法如下:
1、QueueUserWorkItem方法。
本方法是指:向线程池的队列中添加“待办事项”,添加完成后,线程立刻返回,而在“待办事项”中的这个方法需要等到线程池中有可用线程时,才会执行。即线程池不会创建为该方法而创建新的线程,而是等到有空闲线程时,才执行本方法。MSDN的解释如下:

Queues a method for execution, and specifies an object containing data to be used by the method.The method executes when a thread pool thread becomes available.

方法的具体形式如下:

public static bool QueueUserWorkItem(WaitCallback callBack)
public static bool QueueUserWorkItem(WaitCallback callBack,object state)

其中 callBack 的委托定义如下:

[ComVisibleAttribute(true)]
public delegate void WaitCallback(object state)

这儿对QueueUserWorkItem的第二个方法,第二个方法的参数是object,这个很关键。这个参数不仅可以传入回调方法或者是委托的参数值,更可以传入CancellationTokenSource,用作取消操作。详细可见“《CLR via C#》读书笔记-.NET多线程(四)”
2、设定threadpool的线程数
以下的几个方法时设定或获取workerThread和I/O completionPortThreads的数量

public static void GetAvailableThreads(out int workerThreads,out int completionPortThreads)
public static void GetMaxThreads(out int workerThreads,out int completionPortThreads)
public static bool SetMaxThreads(int workerThreads,int completionPortThreads)
public static void GetMinThreads(out int workerThreads,out int completionPortThreads)
public static bool SetMinThreads(int workerThreads,int completionPortThreads)

3、RegisterWaitForSingleObject方法
在ThreadPool中还有一系列的RegisterWaitForSingleObject方法,以其中的一个为例:

public static RegisteredWaitHandle RegisterWaitForSingleObject(
    WaitHandle waitObject,
    WaitOrTimerCallback callBack,
    object state,
    int millisecondsTimeOutInterval,
    bool executeOnlyOnce
)

方法的参数如下:

waitObject
    The WaitHandle to register.Use a WaitHandle other than Mutex.
callBack
    The WaitOrTimerCallback delegate to call when the waitObject parameter is signaled. 
state
    The object that is passed to the delegate. 
millisecondsTimeOutInterval
    The time-out in milliseconds.If the millisecondsTimeOutInterval parameter is 0 (zero), the  
    function tests the object's state and returns immediately.If millisecondsTimeOutInterval is -1, 
    the function's time-out interval never elapses.
executeOnlyOnce
    true to indicate that the thread will no longer wait on the waitObject parameter after the delegate has been called; false to indicate that the timer is reset every time the wait operation completes until the wait is unregistered. 

这个方法意思是说,当waitObject发出信号时,就调用callBack这个方法。相当于为waitObject注册了一个回调方法(callBack),或者说是为回调方法设定了一个是否开始的开关(waitObject)。
网上有网友有例子,在写录音程序时,需要收到录音程序的通知事件,而去做相关事情,因此使用了本方法,具体的地址如下:网友使用本方法的例子
另外,有网友对本方法进行了详细的说明,并且写的很不错,具体的网址在这儿
对于方法的用途,看了上面的说明,应该没有问题,但是我很好奇WaitHandle这个抽象类。因为在《CLR via C#》的第28章也提到了这个抽象类,因此对WaitHandle整理了一下
WaitHandle抽象类
WaitHandle类的唯一作用就是包装一个window内核对象句柄。
WaitHandle类有一个属性 SafeWaitHandle,其保存一个window内核对象。WaitHandle类有如下的几个方法

public virtual bool WaitOne()
...

其方法的作用就是让调用线程等待window底层内核对象收到信号,如果内核对象收到信号,则返回true,否则返回false。
所以RegisterWaitForSingleObject的含义应该是这样的:
执行某个方法/动作,使得内核对象收到了信号,则包含该内核对象的WaitHandle的调用某方法时,得到了true的反馈。当收到这个反馈的时候,就是调用callBack方法。
另外,调用RegisterWaitForSingleObject,就应该要调用Unregister方法,而不是要等待其自动结束。
执行上下文
在执行线程中创建辅助线程时,执行线程的上下文内容会复制到辅助线程中。这样做是合理且正确的。但是存在一个问题,就是会影响到性能。因此在system.threading中有一ExecutionContext 类,其作用就是决定是否将执行线程的上下文复制到辅助线程上。
其主要的方法有:(注意是静态方法)

[SecurityCriticalAttribute]
public static AsyncFlowControl SuppressFlow()
public static void RestoreFlow()
public static bool IsFlowSuppressed()

可在程序中使用ExecutionContext.SuppressFlow(),抑制上下文的“流动”。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章