第三種同步策略關注手動同步技術,.NET Framework 提供了一個經典的技術套件。他們給了程序員使用類似WIN32線程API的底層線程API來創建和管理多線程應用程序的能力。
下面的表顯示了System.Threading 命名空間中可以用於手動同步的一些類。
ManualResetEvent 類
一個ManualResetEvent對象僅能處理signaled(true)或者non-signaled(false)兩個狀態。ManualResetEvent類繼承自WaitHandle類,ManualResetEvent的構造函數接收一個參數用來定義對象的初始值。Set()和Reset()方法返回一個布爾值來指示已經發生的改變是否成功。
下面的代碼NETThreadEvent.cs, 顯示了使用non-signaled狀態的ManualResetEvent類。首先我們創建一個名為mansig 的對象並賦值為false. WaitOne()方法將會等待mansig返回true或者時間超時。由於在等待的時間周期里,mansig的值沒有被置成true, 所以它停止阻塞並返回false:
/************************************* /* Copyright (c) 2012 Daniel Dong * * Author:oDaniel Dong * Blog:o www.cnblogs.com/danielWise * Email:o guofoo@163.com * */ using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace NETThreadEvents { public class NonSignaledManual { public static void Main() { ManualResetEvent mansig; mansig = new ManualResetEvent(false); Console.WriteLine("ManualResetEvent Before WaitOne "); bool b = mansig.WaitOne(1000, false); Console.WriteLine("ManualResetEvent After WaitOne " + b); Console.ReadLine(); } } }
NETThreadEvents 的執行結果如下:
在NETThreadEvents.cs中,我們構造了一個ManualResetEvent對象(構造函數傳值false). 布爾值false將ManualResetEvent對象的初始狀態設置為non-signaled. 然后我們調用WaitHandle基類的WaitOne()方法。WaitOne()方法接受兩個參數。第一個參數是我們想讓線程在WaitOne()方法處等待的時間(毫秒);由於我們將第一個參數設置為1000,所以線程在退出前等待1秒。第二個參數是exitContext. 如果你已經在上下文的同步域中且想退出同步上下文或者你想獲得同步上下文,你應該設置這個參數為true.
程序在WaitOne()方法處阻塞1秒然后由於超時退出。ManualResetEvent的狀態仍然是false, 因此WaitOne()函數返回false.現在我們要看一下如果我們把ManualResetEvent設置為signaled(true)會發生什么:
/************************************* /* Copyright (c) 2012 Daniel Dong * * Author:oDaniel Dong * Blog:o www.cnblogs.com/danielWise * Email:o guofoo@163.com * */ using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace NETThreadEvents { public class NonSignaledManual { public static void Main() { ManualResetEvent mansig; mansig = new ManualResetEvent(true); Console.WriteLine("ManualResetEvent Before WaitOne "); bool b = mansig.WaitOne(1000, false); Console.WriteLine("ManualResetEvent After WaitOne " + b); Console.ReadLine(); } } }
輸出結果如下:
通過將ManualResetEvent的初始狀態設置為signaled, 線程不會在WaitOne()方法等待即便我們設定了1000毫秒的超時時間。在之前的例子中ManualResetEvent是non-signaled, 線程等待這個狀態變成signaled, 但是在1000毫秒之后它超時了。在現在的這個例子中ManualResetEvent狀態已經是non-signaled, 所以沒有理由繼續在WaitOne()方法上等待。為了將ManualResetEvent的狀態改成non-signaled, 我們得調用ManualResetEvent的Reset()方法;如果我們想把ManualResetEvent的狀態改成signaled,我們得調用Set()方法。
下面列表ManualReset.cs, 顯示了使用Reset()方法;另外一個ManualSet.cs 則顯示了Set()方法的使用方法:
/************************************* /* Copyright (c) 2012 Daniel Dong * * Author:oDaniel Dong * Blog:o www.cnblogs.com/danielWise * Email:o guofoo@163.com * */ using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace ManualReset { class Reset { [STAThread] static void Main() { ManualResetEvent manRE; manRE = new ManualResetEvent(true); bool state = manRE.WaitOne(1000, true); Console.WriteLine("ManualResetEvent After first WaitOne " + state); //Change the state to non-signaled manRE.Reset(); state = manRE.WaitOne(5000, true); Console.WriteLine("ManualResetEvent After second WaitOne " + state); Console.ReadLine(); } } }
ManualReset 的輸出結果如下:
在ManualReset中,我們將在ManualResetEvent對象的構造函數中將其狀態設置為signaled(true). 所以線程不會在第一個WaitOne()方法處等待並返回true. 然后我們將ManualResetEvent對象的狀態重置為non-signaled(false), 所以我們看到線程不得不在超時退出之前等待5秒鍾。
在ManualSet.cs 中我們使用Set() 方法:
/************************************* /* Copyright (c) 2012 Daniel Dong * * Author:oDaniel Dong * Blog:o www.cnblogs.com/danielWise * Email:o guofoo@163.com * */ using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace ManualSet { class Set { [STAThread] static void Main(string[] args) { ManualResetEvent manRE; manRE = new ManualResetEvent(false); Console.WriteLine("Before WaitOne"); bool state = manRE.WaitOne(5000, true); Console.WriteLine("ManualResetEvent After first WaitOne " + state); //Change the state to signaled manRE.Set(); state = manRE.WaitOne(5000, true); Console.WriteLine("ManualResetEvent After second WaitOne " + state); Console.ReadLine(); } } }
ManualSet的輸出結果如下:
在Manual Set 中,我們將ManualResetEvent對象的初始狀態設置為non-signaled(false). 所以線程不得不在第一個WaitOne()方法處等待。然后我們使用Set()方法將這個狀態設置為Signaled, 線程拒絕在第二個WaitOne()方法處等待然后退出。
就像WaitOne()方法會等待一個單一事件對象變成signaled一樣,WaitAll()方法等待所有的事件對象變成true或者是signaled狀態,或者它將等待直到發生超時,而WaitAny()方法則等待任意一個時間對象變成true或者是signaled狀態。
下一篇介紹AutoResetEvent, Mutex 以及Interlocked…