《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(),抑制上下文的“流動”。

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