سؤال

لقد قرأت الوثائق على هذا و أعتقد أنني أفهم.وهو AutoResetEvent يعيد عندما رمز يمر من خلال event.WaitOne(), لكن ManualResetEvent لا.

هل هذا صحيح ؟

هل كانت مفيدة؟

المحلول

نعم.هو مثل الفرق بين تولبوث و الباب.على ManualResetEvent هو الباب الذي يجب أن تكون مغلقة (إعادة تعيين) يدويا.على AutoResetEvent هو طريق خاص ، مما يسمح سيارة واحدة للذهاب من خلال تلقائيا إغلاق قبل واحد القادم يمكن أن تحصل من خلال.

نصائح أخرى

فقط تخيل أن AutoResetEvent ينفذ WaitOne() و Reset() واحد الذرية العملية.

الجواب القصير هو نعم.الفرق الأكثر أهمية هو أن AutoResetEvent سوف تسمح فقط واحد في انتظار موضوع للمتابعة.أ ManualResetEvent من ناحية أخرى سوف تبقى السماح خيوط عدة في نفس الوقت حتى تستمر حتى كنت أقول أن تتوقف عن (إعادة تعيين).

مأخوذة من C# 3.0 باختصار الكتاب ، جوزيف Albahari

خيوط في C# - الكتاب الإلكتروني المجاني

أ ManualResetEvent هو الاختلاف على AutoResetEvent.فإنه يختلف في أنه لا إعادة تعيين تلقائيا بعد الخيط من خلال السماح على WaitOne الدعوة ، وذلك وظائف مثل البوابة:داعيا مجموعة بفتح البوابة والسماح أي عدد من المواضيع التي WaitOne في البوابة من خلال ؛ داعيا إعادة إغلاق البوابة ، مما تسبب وربما طابور من النادل أن تتراكم إلى فتح.

واحد يمكن أن تحاكي هذه الوظيفة مع منطقية "gateOpen" حقل (المعلنة مع الكلمة المتقلبة) في تركيبة مع "تدور النوم" – فحص مرارا العلم ، ثم النوم لفترة قصيرة من الوقت.

ManualResetEvents تستخدم أحيانا للإشارة إلى أن عملية كاملة ، أو أن الموضوع هو إكمال التهيئة و هو على استعداد لأداء العمل.

أنا خلقت أمثلة بسيطة لتوضيح الفهم ManualResetEvent مقابل AutoResetEvent.

AutoResetEvent:دعونا نفترض أن لديك 3 عمال الموضوع.إذا كان أي من هذه المواضيع سيتم استدعاء WaitOne() جميع المواضيع الأخرى 2 سيتم إيقاف التنفيذ وانتظر إشارة.وأنا على افتراض أنها تستخدم WaitOne().هو مثل ، إذا كنت لا تعمل ، لا أحد يعمل.في المثال الأول يمكنك أن ترى أن

autoReset.Set();
Thread.Sleep(1000);
autoReset.Set();

عند استدعاء Set() جميع المواضيع سوف تعمل وانتظر إشارة.بعد 1 ثانية أبعث الثانية إشارة أنهم ينفذون والانتظار (WaitOne()).فكر هؤلاء الشباب لكرة القدم لاعبي الفريق و إذا كان لاعب واحد يقول سوف أنتظر حتى مدير يدعو لي ، وغيرها سوف ننتظر حتى مدير يقول لهم على مواصلة (Set())

public class AutoResetEventSample
{
    private AutoResetEvent autoReset = new AutoResetEvent(false);

    public void RunAll()
    {
        new Thread(Worker1).Start();
        new Thread(Worker2).Start();
        new Thread(Worker3).Start();
        autoReset.Set();
        Thread.Sleep(1000);
        autoReset.Set();
        Console.WriteLine("Main thread reached to end.");
    }

    public void Worker1()
    {
        Console.WriteLine("Entered in worker 1");
        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker1 is running {0}", i);
            Thread.Sleep(2000);
            autoReset.WaitOne();
        }
    }
    public void Worker2()
    {
        Console.WriteLine("Entered in worker 2");

        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker2 is running {0}", i);
            Thread.Sleep(2000);
            autoReset.WaitOne();
        }
    }
    public void Worker3()
    {
        Console.WriteLine("Entered in worker 3");

        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker3 is running {0}", i);
            Thread.Sleep(2000);
            autoReset.WaitOne();
        }
    }
}

في هذا المثال يمكنك أن ترى بوضوح أنه عند الضربة الأولى Set() فإنه سيتم السماح لجميع المواضيع الذهاب ، ثم بعد 1 ثانية إشارات جميع المواضيع الانتظار!في أقرب وقت كما كنت وضعت لهم مرة أخرى بغض النظر يدعون WaitOne() داخل, أنها سوف تبقي لأن لديك يدويا الاتصال Reset() وقف كل منهم.

manualReset.Set();
Thread.Sleep(1000);
manualReset.Reset();
Console.WriteLine("Press to release all threads.");
Console.ReadLine();
manualReset.Set();

هو أكثر حول الحكم/اللاعبين العلاقة بغض النظر عن أي لاعب مصاب وانتظر اللعب الآخرين سوف تستمر في العمل.إذا كان الحكم يقول انتظر (Reset()) ثم جميع اللاعبين سوف ننتظر حتى إشارة المقبل.

public class ManualResetEventSample
{
    private ManualResetEvent manualReset = new ManualResetEvent(false);

    public void RunAll()
    {
        new Thread(Worker1).Start();
        new Thread(Worker2).Start();
        new Thread(Worker3).Start();
        manualReset.Set();
        Thread.Sleep(1000);
        manualReset.Reset();
        Console.WriteLine("Press to release all threads.");
        Console.ReadLine();
        manualReset.Set();
        Console.WriteLine("Main thread reached to end.");
    }

    public void Worker1()
    {
        Console.WriteLine("Entered in worker 1");
        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker1 is running {0}", i);
            Thread.Sleep(2000);
            manualReset.WaitOne();
        }
    }
    public void Worker2()
    {
        Console.WriteLine("Entered in worker 2");

        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker2 is running {0}", i);
            Thread.Sleep(2000);
            manualReset.WaitOne();
        }
    }
    public void Worker3()
    {
        Console.WriteLine("Entered in worker 3");

        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker3 is running {0}", i);
            Thread.Sleep(2000);
            manualReset.WaitOne();
        }
    }
}

autoResetEvent.WaitOne()

مشابه

try
{
   manualResetEvent.WaitOne();
}
finally
{
   manualResetEvent.Reset();
}

كما ذرية العملية

حسنا, عادة لا ممارسة جيدة لإضافة 2 الإجابات في نفس الموضوع, ولكن لم أكن أريد أن تحرير/حذف إجابتي السابقة ، حيث أنها يمكن أن تساعد على طريقة أخرى.

الآن, أنا خلقت ، أكثر بكثير شاملة وسهلة الفهم, تشغيل لتعلم وحدة التحكم التطبيق المقتطف أدناه.

فقط تشغيل أمثلة على اثنين من لوحات المفاتيح المختلفة ، ومراقبة السلوك.سوف تحصل على أكثر من ذلك بكثير واضحة عن ما يحدث خلف الكواليس.

دليل إعادة تعيين الحدث

using System;
using System.Threading;

namespace ConsoleApplicationDotNetBasics.ThreadingExamples
{
    public class ManualResetEventSample
    {
        private readonly ManualResetEvent _manualReset = new ManualResetEvent(false);

        public void RunAll()
        {
            new Thread(Worker1).Start();
            new Thread(Worker2).Start();
            new Thread(Worker3).Start();
            Console.WriteLine("All Threads Scheduled to RUN!. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Main Thread is waiting for 15 seconds, observe 3 thread behaviour. All threads run once and stopped. Why? Because they call WaitOne() internally. They will wait until signals arrive, down below.");
            Thread.Sleep(15000);
            Console.WriteLine("1- Main will call ManualResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("2- Main will call ManualResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("3- Main will call ManualResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("4- Main will call ManualResetEvent.Reset() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Reset();
            Thread.Sleep(2000);
            Console.WriteLine("It ran one more time. Why? Even Reset Sets the state of the event to nonsignaled (false), causing threads to block, this will initial the state, and threads will run again until they WaitOne().");
            Thread.Sleep(10000);
            Console.WriteLine();
            Console.WriteLine("This will go so on. Everytime you call Set(), ManualResetEvent will let ALL threads to run. So if you want synchronization between them, consider using AutoReset event, or simply user TPL (Task Parallel Library).");
            Thread.Sleep(5000);
            Console.WriteLine("Main thread reached to end! ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);

        }

        public void Worker1()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine("Worker1 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                // this gets blocked until _autoReset gets signal
                _manualReset.WaitOne();
            }
            Console.WriteLine("Worker1 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker2()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine("Worker2 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                // this gets blocked until _autoReset gets signal
                _manualReset.WaitOne();
            }
            Console.WriteLine("Worker2 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker3()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine("Worker3 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                // this gets blocked until _autoReset gets signal
                _manualReset.WaitOne();
            }
            Console.WriteLine("Worker3 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
    }

}

Manual Reset Event Output

لصناعة السيارات في إعادة تعيين الحدث

using System;
using System.Threading;

namespace ConsoleApplicationDotNetBasics.ThreadingExamples
{
    public class AutoResetEventSample
    {
        private readonly AutoResetEvent _autoReset = new AutoResetEvent(false);

        public void RunAll()
        {
            new Thread(Worker1).Start();
            new Thread(Worker2).Start();
            new Thread(Worker3).Start();
            Console.WriteLine("All Threads Scheduled to RUN!. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Main Thread is waiting for 15 seconds, observe 3 thread behaviour. All threads run once and stopped. Why? Because they call WaitOne() internally. They will wait until signals arrive, down below.");
            Thread.Sleep(15000);
            Console.WriteLine("1- Main will call AutoResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("2- Main will call AutoResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("3- Main will call AutoResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("4- Main will call AutoResetEvent.Reset() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Reset();
            Thread.Sleep(2000);
            Console.WriteLine("Nothing happened. Why? Becasuse Reset Sets the state of the event to nonsignaled, causing threads to block. Since they are already blocked, it will not affect anything.");
            Thread.Sleep(10000);
            Console.WriteLine("This will go so on. Everytime you call Set(), AutoResetEvent will let another thread to run. It will make it automatically, so you do not need to worry about thread running order, unless you want it manually!");
            Thread.Sleep(5000);
            Console.WriteLine("Main thread reached to end! ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);

        }

        public void Worker1()
        {
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("Worker1 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(500);
                // this gets blocked until _autoReset gets signal
                _autoReset.WaitOne();
            }
            Console.WriteLine("Worker1 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker2()
        {
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("Worker2 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(500);
                // this gets blocked until _autoReset gets signal
                _autoReset.WaitOne();
            }
            Console.WriteLine("Worker2 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker3()
        {
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("Worker3 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(500);
                // this gets blocked until _autoReset gets signal
                _autoReset.WaitOne();
            }
            Console.WriteLine("Worker3 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
    }

}

Auto Reset Event Output

نعم.هذا هو الصحيح تماما.

هل يمكن أن نرى ManualResetEvent كطريقة للإشارة إلى الدولة.شيء على (تعيين) أو off (إعادة تعيين).تواجد مع بعض المدة.أي موضوع في انتظار تلك الدولة أن يحدث يمكن المضي قدما.

وهو AutoResetEvent هو أكثر مماثلة إلى إشارة.طلقة واحدة إشارة إلى أن شيئا ما قد حدث.حدوث بدون أي مدة.عادة ولكن ليس بالضرورة "شيء ما" الذي حدث هو صغير و يحتاج إلى معالجة موضوع واحد - وبالتالي إعادة تعيين تلقائي بعد موضوع واحد قد استهلكت الحدث.

نعم, هذا صحيح.

يمكنك الحصول على فكرة من خلال استخدام هذين.

إذا كنت بحاجة إلى أن أقول أن الانتهاء من بعض الأعمال الأخرى (المواضيع) في انتظار هذا يمكن المضي قدما الآن, يجب عليك استخدام ManualResetEvent.

إذا كنت بحاجة إلى المتبادلة الوصول الحصري إلى أي مورد, يجب عليك استخدام AutoResetEvent.

AutoResetEvent يحافظ متغير منطقية في الذاكرة.إذا كان متغير منطقية خاطئة ثم كتل موضوع و إذا كان متغير منطقي صحيح أنه يفرج الموضوع.

عندما كنا مثيل AutoResetEvent كائن ، ونحن تمرير القيمة الافتراضية قيمة منطقية في منشئ.وفيما يلي جملة من مثيل AutoResetEvent الكائن.

AutoResetEvent autoResetEvent = new AutoResetEvent(false);

WaitOne طريقة

هذا الأسلوب كتل الترابط الحالي و تنتظر إشارة من الصفحات الأخرى.WaitOne الأسلوب يضع موضوع الحالي في النوم الخيط الدولة.WaitOne الأسلوب بإرجاع true إذا كان يتلقى إشارة آخر بإرجاع false.

autoResetEvent.WaitOne();

الثانية الزائد من WaitOne طريقة الانتظار للحصول على عدد محدد من الثواني.إذا أنها لا تحصل على أي إشارة ترابط وتواصل عملها.

static void ThreadMethod()
{
    while(!autoResetEvent.WaitOne(TimeSpan.FromSeconds(2)))
    {
        Console.WriteLine("Continue");
        Thread.Sleep(TimeSpan.FromSeconds(1));
    }

    Console.WriteLine("Thread got signal");
}

اتصلنا WaitOne طريقة تمرير 2 ثانية كما الحجج.في حين حلقة ، تنتظر إشارة لمدة 2 ثانية ثم استمرار العمل.عندما الخيط حصلت على إشارة WaitOne ترجع صحيح ومخارج حلقة طباعة "الخيط حصلت على إشارة".

تعيين طريقة

AutoResetEvent تعيين طريقة إرسال إشارة إلى انتظار الموضوع على المضي قدما في عملها.وفيما يلي جملة من استدعاء مجموعة الأسلوب.

autoResetEvent.Set();

ManualResetEvent يحافظ متغير منطقية في الذاكرة.عندما متغير منطقية خاطئة ثم كتل جميع المواضيع و عندما متغير منطقي صحيح أنه يفرج كل المواضيع.

عندما كنا مثيل ManualResetEvent نحن تهيئة مع الافتراضي قيمة منطقية.

ManualResetEvent manualResetEvent = new ManualResetEvent(false);

في التعليمات البرمجية أعلاه ، نحن تهيئة ManualResetEvent مع قيمة كاذبة, وهذا يعني أن جميع المواضيع التي يدعو WaitOne طريقة منع حتى بعض الصفحات المكالمات مجموعة الأسلوب ().

إذا نحن تهيئة ManualResetEvent مع القيمة الحقيقية ، جميع المواضيع التي يدعو WaitOne الطريقة لن كتلة مجانا على المضي قدما.

WaitOne طريقة

هذا الأسلوب كتل الترابط الحالي و تنتظر إشارة من الصفحات الأخرى.إرجاع true إذا به يتلقى إشارة آخر بإرجاع false.

وفيما يلي جملة من يدعو WaitOne الأسلوب.

manualResetEvent.WaitOne();

في الثانية الزائد من WaitOne الطريقة ، يمكننا تحديد الوقت الفاصل حتى الترابط الحالي تنتظر إشارة.إذا كان في وقت الداخلية ، فإنه لا يتلقى إشارة يعود كاذبة ويذهب إلى السطر التالي من طريقة.

وفيما يلي جملة من يدعو WaitOne الأسلوب مع الفاصل الزمني.

bool isSignalled = manualResetEvent.WaitOne(TimeSpan.FromSeconds(5));

يجب تحديد 5 ثوان في WaitOne الأسلوب.إذا كان manualResetEvent كائن لا يتلقى إشارة بين 5 ثوان ، تعيين isSignalled متغير إلى false.

تعيين طريقة

ويستخدم هذا الأسلوب من أجل إرسال إشارة إلى جميع المواضيع انتظار.مجموعة() طريقة تعيين ManualResetEvent كائن متغير منطقية إلى true.جميع المواضيع انتظار محظورة والمضي قدما.

وفيما يلي جملة من استدعاء مجموعة() الأسلوب.

manualResetEvent.Set();

إعادة تعيين طريقة

مرة واحدة ونحن ندعو مجموعة() الأسلوب على ManualResetEvent كائن ، منطقية لا يزال صحيحا.لإعادة تعيين قيمة يمكننا إعادة استخدام طريقة ().إعادة تعيين طريقة تغيير القيمة المنطقية false.

وفيما يلي جملة من استدعاء الأسلوب إعادة تعيين.

manualResetEvent.Reset();

يجب أن نطلق على الفور إعادة تعيين طريقة بعد استدعاء مجموعة الأسلوب إذا كنا نريد أن نرسل إشارة إلى مواضيع عدة مرات.

إذا أردت أن تفهم AutoResetEvent و ManualResetEvent تحتاج إلى فهم ليس خيوط ولكن يقطع!

.صافي يريد أن تستحضر البرمجة ذات المستوى المنخفض الأكثر بعدا ممكن.

وهو يقطع شيء المستخدمة في البرمجة ذات المستوى المنخفض الذي يساوي إشارة إلى أن من انخفاض أصبحت عالية (أو العكس).عندما يحدث هذا البرنامج يقطع العادية التنفيذ والتحرك تنفيذ مؤشر إلى وظيفة يتعامل مع هذا الحدث.

أول شيء فعله عندما يقطع حدث هو إعادة تعيين حالته ، becosa الأجهزة يعمل في هذه الطريقة:

  1. دبوس توصيل إشارة والأجهزة الاستماع إلى تغيير (إشارة يمكن أن يكون اثنين فقط من الدول).
  2. إذا كانت الإشارة التغييرات يعني أن شيئا ما حدث والأجهزة وضع الذاكرة متغير إلى الدولة حدث (و يظل هكذا حتى إذا كانت الإشارة تغيير مرة أخرى).
  3. البرنامج لاحظ أن المتغير تغيير الدول ونقل التنفيذ إلى التعامل مع الدالة.
  4. هنا أول شيء فعله أن تكون قادرة على الاستماع مرة أخرى هذه المقاطعة ، إعادة تعيين هذه الذاكرة متغير الدولة لا حدث.

هذا هو الفرق بين ManualResetEvent و AutoResetEvent.
إذا ManualResetEvent يحدث وأنا لا إعادة عليه ، حدث المرة القادمة أنا سوف لا تكون قادرة على الاستماع.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top