.net 4.0新特性-CountDownEvent

来源:互联网 发布:网络直播室 编辑:程序博客网 时间:2024/05/16 11:48

也称为反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());    }}
可以看到同时进入三个线程
image

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

http://msdn.microsoft.com/zh-cn/magazine/cc163427.aspx