久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

.Net CLR 中的同步機(jī)制(三): AutoResetEvent和ManualResetEvent

 賈朋亮博客 2015-02-26

這里所說的事件是最基本的控制同步原語,不同于.Net語言中的事件,。在任何時刻,,一個事件可能處于兩種狀態(tài)之一:已觸發(fā)或者未觸發(fā),,如果一個線程在一個未觸發(fā)的事件上面等待,那么只有當(dāng)這個事件的狀態(tài)變成已觸發(fā)時,,這個線程才能繼續(xù)執(zhí)行,;如果在等待時,,事件已經(jīng)處于已觸發(fā)狀態(tài),,那么線程將立即繼續(xù)執(zhí)行。

Windows提供了兩種特殊的事件對象類型來實(shí)現(xiàn)線程之間的合作:自動設(shè)置事件和手動設(shè)置事件,。他們都屬于內(nèi)核對象,。這兩種事件的差別是:當(dāng)AutoResetEvent被觸發(fā)時,只有一個線程可以看到這個信號,,當(dāng)線程看見這個信號時候,,AutoResetEvent會自動切換到未觸發(fā)狀態(tài)。而ManualResetEvent需要手動調(diào)用方法來切換到未觸發(fā)狀態(tài),。如果有多個線程都在等待一個AutoResetEvent的觸發(fā)狀態(tài),,系統(tǒng)將會為這些等待的線程建立一個隊(duì)列,當(dāng)這個AutoResetEvent狀態(tài)切換到觸發(fā)狀態(tài)的時候,,只有一個線程可以看見這個狀態(tài)的變化繼續(xù)執(zhí)行,,其他的線程還必須要等到下一次狀態(tài)切換到已觸發(fā)。我們并不能保證先等待的線程會先繼續(xù)執(zhí)行,,這里面涉及到內(nèi)核線程調(diào)度的一些原因,,比如優(yōu)先級。 AutoResetEvent如果在沒有線程等待的情況下,,切換到已觸發(fā)狀態(tài),,那么以后第一個等待這個事件的線程將可以繼續(xù)執(zhí)行。然而對于ManualResetEvent,, 所有等待的線程在ManualResetEvent設(shè)置成已觸發(fā)狀態(tài)的時候,,都將繼續(xù)執(zhí)行。

一個簡單的AutoResetEvent示例:

復(fù)制代碼
 1 class Program 
 2     { 
 3         static AutoResetEvent are = new AutoResetEvent(false);
 4 
 5         static void Main() 
 6         { 
 7             new Thread(Waiter).Start(); 
 8             Thread.Sleep(1000);              
 9             are.Set();
10 
11             Console.ReadLine(); 
12         }
13 
14         static void Waiter() 
15         { 
16             Console.WriteLine("Waiting..."); 
17             are.WaitOne();                
18             Console.WriteLine("Notified"); 
19         } 
20     }
復(fù)制代碼

 

值得一提的是,,AutoResetEvent的WaitOne方法,,如果實(shí)參是0的話,則表示查看該AutoResetEvent的狀態(tài),,不會阻塞操作,。

下面是使用AutoResetEvent實(shí)現(xiàn)的BlockingQueue,使用AutoResetEvent的阻塞隊(duì)列效率上要比Monitor和4.0的BlockingCollection差很多,。

復(fù)制代碼
public class BlockingQueueWithEvent<T>
    {
        private Queue<T> _queue = new Queue<T>();
        private Mutex _mutex = new Mutex();
        private AutoResetEvent _event = new AutoResetEvent(false);

        public void Enqueue(T obj)
        {
            _mutex.WaitOne();

            try
            {
                _queue.Enqueue(obj);
            }
            finally 
            {
                _mutex.ReleaseMutex();
            }
            //有一個可用項(xiàng),,喚醒一個消費(fèi)者。
            _event.Set();
        }

        public T Dequeue()
        {
            T obj = default(T);

            bool taken = true;

            _mutex.WaitOne();

            try
            {
                while (_queue.Count == 0)
                {
                    taken = false;
                    WaitHandle.SignalAndWait(_mutex, _event);
                    _mutex.WaitOne();
                    taken = true;
                }

                obj = _queue.Dequeue();
            }
            finally
            {
                if (taken)
                {
                    _mutex.ReleaseMutex();
                }
            }

            return obj;
        }
    }
復(fù)制代碼

代碼中使用到了 WaitHandle.SignalAndWait(_mutex, _event) 方法,。這是一個原子操作,,表示給第一個參數(shù)_mutex一個信號,,釋放上面的鎖,。然后在第二個參數(shù)上面等待,。

 

AutoResetEvent和ManualResetEvent這兩種事件都沒有所有者的概念,,任何線程都可以切換事件的狀態(tài),。同樣,他們也沒有遞歸性質(zhì),,不像Mutex和Semaphore,,內(nèi)部有一個計(jì)數(shù)器,。所以多次執(zhí)行Set或Reset方法都沒有任何其他的效果,當(dāng)事件已經(jīng)處于已觸發(fā)狀態(tài)時,多次調(diào)用Set實(shí)際上是被忽略,。這個特性需要我們在開發(fā)程序中特別注意,,往往這個喚醒(Set)會被遺失。比如說有兩個生產(chǎn)者,,前后分別向隊(duì)列中放了一個項(xiàng),。而消費(fèi)者在收到喚醒信號的時候只會去隊(duì)列中拿走一個項(xiàng),。

這兩個事件都會在擁有該事件的應(yīng)用程序域銷毀的時候自動銷毀,。

在 .NET Framework 4中,,當(dāng)?shù)却龝r間預(yù)計(jì)非常短時,并且當(dāng)事件不會跨越進(jìn)程邊界時,,可使用 ManualResetEventSlim 類以獲得更好的性能,。因?yàn)樗锩嬖谀承┑胤绞褂昧俗孕岣吡诵阅堋?/p>

在.NET Framework 4中,,還提供了其他兩個基于ManualResetEventSlim的新類型,,CountdownEvent和ManualResetEventSlim,他們都是使用ManualResetEventSlim來實(shí)現(xiàn)的,。

下面是CountdownEvent的示例,,表示CountdownEvent需要收到3個事件信號才會繼續(xù)執(zhí)行:

 

復(fù)制代碼
static CountdownEvent cde = new CountdownEvent(3);

static void TestCountDownEvent()
        {
            Task.Factory.StartNew(() =>
                {
                    Thread.Sleep(1000);
                    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
                    cde.Signal();
                });
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(1000);
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
                cde.Signal();
            });
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(1000);
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
                cde.Signal();
            });
            cde.Wait();
            Console.WriteLine("all are finished.");
        }
復(fù)制代碼

 

結(jié)果:

N`[T33XBCFC3HF}96{CG21T

 

Barrier也有類似的功能,但是它不像CountdownEvent,,CountdownEvent滿足條件之后就一直執(zhí)行下去了,,但Barrier有SignalAndWait,信號以后還繼續(xù)等待,。有一種“步驟”的感覺,。因?yàn)橐粡垐D:

LS8136@DJD$1PT`KADDFE`Y

下面一個例子就是3個線程都打印0到4,5個數(shù)字,。每個線程每打印一個數(shù)字,,都需要停下來等待其他的線程完成這一輪打印,然后齊頭并進(jìn)打印下面一個數(shù)字,。

 

復(fù)制代碼
        static void Main()
        {
            TestBarrier();
            Console.ReadLine();
        }

        static Barrier b = new Barrier(3);

        static void TestBarrier()
        {
            Task.Factory.StartNew(TestBarrierMethod);
            Task.Factory.StartNew(TestBarrierMethod);
            Task.Factory.StartNew(TestBarrierMethod);
        }

        private static void TestBarrierMethod()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.Write(i + " ");
                b.SignalAndWait();
            }
        }
復(fù)制代碼

 

 

N@763NE73{PKE6AN78[45{J

 

測試代碼在這里下載

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多