.net 4.0新特性-CountDownEvent
2010-06-10 12:56 Clingingboy 阅读(1365) 评论(0) 编辑 收藏 举报也称为反Semaphore 作用:统计其他线程结束工作,监听计数为0时,触发操作.
与Semaphore形成对比,Semaphore有最大资源数,当计数为0时(即资源不够用时)则阻塞线程
1.Semaphore
初始化时,资源为0,调用Release方法释放资源
using System; using System.Threading; public class Example { // A semaphore that simulates a limited resource pool. // private static Semaphore _pool; // A padding interval to make the output more orderly. private static int _padding; public static void Main() { // Create a semaphore that can satisfy up to three // concurrent requests. Use an initial count of zero, // so that the entire semaphore count is initially // owned by the main program thread. // _pool = new Semaphore(0, 3); // Create and start five numbered threads. // for (int i = 1; i <= 5; i++) { Thread t = new Thread(new ParameterizedThreadStart(Worker)); // Start the thread, passing the number. // t.Start(i); } // Wait for half a second, to allow all the // threads to start and to block on the semaphore. // Thread.Sleep(500); // The main thread starts out holding the entire // semaphore count. Calling Release(3) brings the // semaphore count back to its maximum value, and // allows the waiting threads to enter the semaphore, // up to three at a time. // Console.WriteLine("Main thread calls Release(3)."); _pool.Release(3); Console.WriteLine("Main thread exits."); } private static void Worker(object num) { // Each worker thread begins by requesting the // semaphore. Console.WriteLine("Thread {0} begins " + "and waits for the semaphore.", num); _pool.WaitOne(); // A padding interval to make the output more orderly. int padding = Interlocked.Add(ref _padding, 100); Console.WriteLine("Thread {0} enters the semaphore.", num); // The thread's "work" consists of sleeping for // about a second. Each thread "works" a little // longer, just to make the output more orderly. // Thread.Sleep(1000 + padding); Console.WriteLine("Thread {0} releases the semaphore.", num); Console.WriteLine("Thread {0} previous semaphore count: {1}", num, _pool.Release()); } }可以看到同时进入三个线程
2.CountDownEvent
初始化当前线程计数即为1,然后在其他线程运行前调用AddCount进行计数,执行完毕后调用Signal方法减少计数.等所有线程计数后,还需要在当前线程中调用Signal,等所有工作完成计数为0时,Wait方法将不再阻塞
using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; class CancelableCountdowEvent { class Data { public int Num { get; set; } public Data(int i) { Num = i; } public Data() { } } class DataWithToken { public CancellationToken Token { get; set; } public Data Data { get; private set; } public DataWithToken(Data data, CancellationToken ct) { this.Data = data; this.Token = ct; } } static IEnumerable<Data> GetData() { return new List<Data>() { new Data(1), new Data(2), new Data(3), new Data(4), new Data(5) }; } static void ProcessData(object obj) { DataWithToken dataWithToken = (DataWithToken)obj; if (dataWithToken.Token.IsCancellationRequested) { Console.WriteLine("Canceled before starting {0}", dataWithToken.Data.Num); return; } for (int i = 0; i < 1000; i++) { // Increase this value to slow down the program. Thread.SpinWait(100000); } Console.WriteLine("Processed {0}", dataWithToken.Data.Num); } static void Main(string[] args) { EventWithCancel(); Console.WriteLine("Press enter to exit."); Console.ReadLine(); } static void EventWithCancel() { IEnumerable<Data> source = GetData(); CancellationTokenSource cts = new CancellationTokenSource(); //Enable cancellation request from a simple UI thread. Task.Factory.StartNew(() => { if (Console.ReadKey().KeyChar == 'c') cts.Cancel(); }); // Event must have a count of at least 1 CountdownEvent e = new CountdownEvent(1); // fork work: foreach (Data element in source) { DataWithToken item = new DataWithToken(element, cts.Token); // Dynamically increment signal count. e.AddCount(); ThreadPool.QueueUserWorkItem(delegate(object state) { ProcessData(state); //if (!cts.Token.IsCancellationRequested) e.Signal(); }, item); } //// Decrement the signal count by the one we added //// in the constructor. e.Signal(); //// The first element could be run on this thread. //// Join with work or catch cancellation. try { e.Wait(cts.Token); } catch (OperationCanceledException oce) { if (oce.CancellationToken == cts.Token) { Console.WriteLine("User canceled."); } else throw; //We don't know who canceled us! } e.Dispose(); //... } //end method } //end class
参考:
http://www.cnblogs.com/shanyou/archive/2009/10/27/1590890.html
http://blogs.msdn.com/b/pfxteam/archive/2008/06/21/8629821.aspx