ManualResetEvent และ AutoResetEvent ใน. NET แตกต่างกันอย่างไร


532

ฉันได้อ่านเอกสารเกี่ยวกับเรื่องนี้แล้วและฉันคิดว่าฉันเข้าใจ AutoResetEventรีเซ็ตเมื่อรหัสผ่านevent.WaitOne()แต่ManualResetEventไม่ได้

ถูกต้องหรือไม่


2
อาจ av นี้จะช่วยให้เข้าใจความแตกต่างyoutube.com/watch?v=xaaRBh07N34
Vinod Srivastav

คำตอบ:


920

ใช่. มันเหมือนความแตกต่างระหว่างโทลเวย์กับประตู ManualResetEventเป็นประตูซึ่งจะต้องมีการปิด (ตั้งค่า) ด้วยตนเอง AutoResetEventเป็นด่านที่ช่วยให้รถคันหนึ่งไปโดยอัตโนมัติและปิดก่อนที่หนึ่งต่อไปจะได้รับผ่าน


166
นั่นคือการเปรียบเทียบที่ดี
twk

ยิ่งแย่ไปกว่านั้นอย่ารอนานเพื่อตั้งค่า ARE เป็น WaitOne มิฉะนั้นจะถูกตั้งค่าใหม่ในระหว่างนี้ มีหัวข้อที่ถูกทอดทิ้งจำนวนมากด้วย
Oliver Friedrich

24
หรือเหมือนประตูและประตูหมุน
Constantin

9
โอ้นั่นคือเหตุผลที่พวกเขาตั้งชื่อสิ่งที่พวกเขา
Arlen Beiler

1
@DanGoldstein ดีเพราะนี่ยังไม่ปิดและในกรณีที่คนอื่นต้องการ: msdn.microsoft.com/en-us/library/ …
Phil N DeBlanc

124

แค่คิดว่ามันAutoResetEventดำเนินการWaitOne()และReset()เป็นปฏิบัติการอะตอมเดียว


16
ยกเว้นว่าถ้าคุณดำเนินการ WaitOne และรีเซ็ตเป็นการดำเนินการแบบปรมาณูเดียวในเหตุการณ์ ManualResetEvent มันจะยังคงทำสิ่งที่แตกต่างจาก AutoResetEvent ManualResetEvent ปล่อยเธรดการรอทั้งหมดในเวลาเดียวกันโดยที่ AutoResetEvent รับประกันว่าจะปล่อยเธรดที่รอเพียงเธรดเดียวเท่านั้น
Martin Brown

55

คำตอบสั้น ๆ คือใช่ ความแตกต่างที่สำคัญที่สุดคือ AutoResetEvent จะอนุญาตให้เธรดที่รอเพียงหนึ่งเธรดดำเนินการต่อ ManualResetEvent ในอีกทางหนึ่งจะอนุญาตให้เธรดหลายตัวพร้อมกันเพื่อดำเนินการต่อจนกว่าคุณจะบอกให้หยุด (รีเซ็ต)


36

นำมาจากหนังสือสรุป C # 3.0 โดย Joseph Albahari

เกลียวใน C # - E-Book ฟรี

ManualResetEvent เป็นรูปแบบของ AutoResetEvent มันแตกต่างกันโดยที่มันจะไม่รีเซ็ตโดยอัตโนมัติหลังจากที่เธรดปล่อยให้ผ่านการเรียก WaitOne และฟังก์ชั่นเช่น gate: การเรียก Set Set จะเปิด gate ซึ่งอนุญาตให้มีเธรดจำนวนใด ๆ ที่ WaitOne ที่เกตผ่าน; การรีเซ็ตการเรียกปิดประตูทำให้คิวของบริกรที่จะสะสมจนกว่าจะเปิดต่อไป

เราสามารถจำลองการทำงานนี้ด้วยฟิลด์ "gateOpen" บูลีน (ประกาศด้วยคำสำคัญระเหย) ร่วมกับ "สปิน - หลับ" - ตรวจสอบสถานะซ้ำแล้วซ้ำอีกจากนั้นก็หลับเป็นระยะเวลาสั้น ๆ

ManualResetEvents บางครั้งใช้เพื่อส่งสัญญาณว่าการดำเนินการเฉพาะเสร็จสมบูรณ์หรือว่าการเริ่มต้นของเธรดเสร็จสมบูรณ์และพร้อมที่จะทำงาน


19

ฉันสร้างตัวอย่างง่ายๆเพื่อชี้แจงทำความเข้าใจของVSManualResetEventAutoResetEvent

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();
        }
    }
}

13

autoResetEvent.WaitOne()

เหมือนกับ

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

เป็นการดำเนินการปรมาณู


นี่เป็นเพียงแนวคิดที่ถูกต้อง แต่ไม่จริง ระหว่าง WaitOne และสวิตช์รีเซ็ตบริบทอาจเกิดขึ้น สิ่งนี้สามารถนำไปสู่ข้อบกพร่องที่ลึกซึ้ง
hofingerandi

2
คุณสามารถโหวตได้ไหม ไม่มีใครทำบล็อกรหัสที่สองที่นี่จริงมันเป็นเรื่องของการเข้าใจความแตกต่าง
vezenkov

11

ตกลงปกติแล้วมันไม่ได้เป็นวิธีปฏิบัติที่ดีในการเพิ่ม 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);
        }
    }

}

รีเซ็ตเหตุการณ์เอาท์พุท

เหตุการณ์รีเซ็ตอัตโนมัติ

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);
        }
    }

}

รีเซ็ตผลลัพธ์ของเหตุการณ์โดยอัตโนมัติ


นี่เป็นวิธีที่ดีที่สุดในการทำความเข้าใจทุกอย่างคัดลอกโค้ดและรันทุกอย่างในขณะที่เปลี่ยนบางสิ่งเข้าใจได้เป็นอย่างดีในตอนนี้
4659

8

AutoResetEventรักษาตัวแปรบูลีนในหน่วยความจำ หากตัวแปรบูลีนเป็นเท็จมันจะบล็อกเธรดและหากตัวแปรบูลีนเป็นจริงมันจะปลดบล็อกเธรด

เมื่อเรายกตัวอย่างวัตถุ AutoResetEvent เราจะส่งผ่านค่าเริ่มต้นของค่าบูลีนในตัวสร้าง ด้านล่างเป็นไวยากรณ์ของอินสแตนซ์ของวัตถุ AutoResetEvent

AutoResetEvent autoResetEvent = new AutoResetEvent(false);

วิธี WaitOne

วิธีการนี้จะบล็อกเธรดปัจจุบันและรอสัญญาณจากเธรดอื่น เมธอด WaitOne จะทำให้เธรดปัจจุบันอยู่ในสถานะสลีปของเธรด เมธอด WaitOne จะส่งกลับค่าจริงหากได้รับสัญญาณอื่นจะคืนค่าเป็นเท็จ

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 จะส่งกลับค่าจริงและออกจากลูปแล้วพิมพ์ "Thread got signal"

กำหนดวิธีการ

วิธีการตั้งค่า AutoResetEvent ส่งสัญญาณไปยังเธรดที่รอเพื่อดำเนินการต่อ ด้านล่างเป็นไวยากรณ์ของการเรียกวิธีการตั้งค่า

autoResetEvent.Set();

ManualResetEventรักษาตัวแปรบูลีนในหน่วยความจำ เมื่อตัวแปรบูลีนเป็นเท็จมันจะบล็อกเธรดทั้งหมดและเมื่อตัวแปรบูลีนเป็นจริงมันจะปลดบล็อกเธรดทั้งหมด

เมื่อเรายกตัวอย่าง ManualResetEvent เราจะเริ่มต้นมันด้วยค่าบูลีนเริ่มต้น

ManualResetEvent manualResetEvent = new ManualResetEvent(false);

ในรหัสข้างต้นเราเริ่มต้น ManualResetEvent ด้วยค่าเท็จนั่นหมายถึงกระทู้ทั้งหมดที่เรียกวิธี WaitOne จะปิดกั้นจนกว่าบางกระทู้เรียกวิธีการ Set ()

หากเราเริ่มต้น ManualResetEvent ด้วยค่าจริงเธรดทั้งหมดที่เรียกใช้เมธอด WaitOne จะไม่บล็อกและฟรีเพื่อดำเนินการต่อไป

วิธี WaitOne

วิธีการนี้จะบล็อกเธรดปัจจุบันและรอสัญญาณจากเธรดอื่น มันจะกลับมาจริงถ้ามันได้รับสัญญาณอื่นกลับเท็จ

ด้านล่างเป็นไวยากรณ์ของการเรียกวิธี WaitOne

manualResetEvent.WaitOne();

ในโอเวอร์โหลดที่สองของเมธอด WaitOne เราสามารถระบุช่วงเวลาจนกระทั่งเธรดปัจจุบันรอสัญญาณ หากภายในระยะเวลาภายในจะไม่ได้รับสัญญาณที่ส่งกลับเท็จและเข้าสู่วิธีการบรรทัดถัดไป

ด้านล่างนี้เป็นรูปแบบของการเรียกวิธี WaitOne พร้อมช่วงเวลา

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

เราได้ระบุ 5 วินาทีในวิธี WaitOne หากอ็อบเจ็กต์ manualResetEvent ไม่ได้รับสัญญาณระหว่าง 5 วินาทีมันจะตั้งค่าตัวแปร isSignalled เป็น false

กำหนดวิธีการ

วิธีนี้ใช้สำหรับส่งสัญญาณไปยังเธรดที่รออยู่ทั้งหมด Set () วิธีการตั้งค่าตัวแปรบูลีน ManualResetEvent วัตถุเป็นจริง เธรดที่รอทั้งหมดจะถูกปลดบล็อกและดำเนินการต่อไป

ด้านล่างเป็นไวยากรณ์ของการโทร Set () วิธีการ

manualResetEvent.Set();

รีเซ็ตวิธี

เมื่อเราเรียกใช้เมธอด Set () บนวัตถุ ManualResetEvent บูลีนจะยังคงเป็นจริง ในการรีเซ็ตค่าเราสามารถใช้วิธีรีเซ็ต () วิธีการรีเซ็ตเปลี่ยนค่าบูลีนเป็นเท็จ

ด้านล่างเป็นไวยากรณ์ของการเรียกใช้วิธีการตั้งค่าใหม่

manualResetEvent.Reset();

เราจะต้องเรียกใช้วิธีการรีเซ็ตทันทีหลังจากเรียกวิธีการตั้งค่าถ้าเราต้องการส่งสัญญาณไปยังกระทู้หลายครั้ง


7

ใช่. ถูกต้องอย่างแน่นอน

คุณสามารถดู ManualResetEvent เป็นวิธีการระบุสถานะ บางสิ่งบางอย่างเปิดอยู่ (ตั้งค่า) หรือปิด (รีเซ็ต) เหตุการณ์ที่เกิดขึ้นในระยะเวลาหนึ่ง เธรดใด ๆ ที่รอสถานะนั้นจะเกิดขึ้นได้

AutoResetEvent เปรียบได้กับสัญญาณมากกว่า การยิงครั้งเดียวบ่งชี้ว่ามีบางอย่างเกิดขึ้น เหตุการณ์ที่เกิดขึ้นโดยไม่มีระยะเวลาใด ๆ โดยทั่วไปแล้ว แต่ไม่จำเป็นว่า "บางอย่าง" ที่เกิดขึ้นมีขนาดเล็กและจำเป็นต้องจัดการโดยเธรดเดี่ยว - ดังนั้นการรีเซ็ตอัตโนมัติหลังจากเธรดเดี่ยวใช้เหตุการณ์


7

ใช่ถูกแล้ว.

คุณสามารถรับแนวคิดจากการใช้สองสิ่งนี้

หากคุณจำเป็นต้องบอกว่าคุณทำงานเสร็จแล้วและงานอื่น ๆ (เธรด) ที่รอให้ขั้นตอนนี้สามารถดำเนินการต่อได้คุณควรใช้ ManualResetEvent

หากคุณต้องการเข้าถึงทรัพยากรใด ๆ ร่วมกันคุณควรใช้ AutoResetEvent


1

หากคุณต้องการที่จะเข้าใจ AutoResetEvent และ ManualResetEvent คุณต้องเข้าใจไม่เกลียว แต่ขัดจังหวะ!

.NET ต้องการคิดในการเขียนโปรแกรมระดับต่ำสุดไกลที่สุด

การขัดจังหวะเป็นสิ่งที่ใช้ในการเขียนโปรแกรมระดับต่ำซึ่งเท่ากับสัญญาณที่จากต่ำกลายเป็นสูง (หรือ viceversa) เมื่อสิ่งนี้เกิดขึ้นโปรแกรมจะขัดจังหวะการทำงานปกติและเลื่อนตัวชี้การเรียกใช้งานไปยังฟังก์ชันที่จัดการกับเหตุการณ์นี้

สิ่งแรกที่ต้องทำเมื่อมีการขัดจังหวะเกิดขึ้นคือการรีเซ็ตสถานะเนื่องจากฮาร์ดแวร์ทำงานในลักษณะนี้:

  1. พินเชื่อมต่อกับสัญญาณและฮาร์ดแวร์ฟังเพื่อเปลี่ยน (สัญญาณอาจมีเพียงสองสถานะ)
  2. หากการเปลี่ยนแปลงสัญญาณหมายความว่ามีบางสิ่งเกิดขึ้นและฮาร์ดแวร์นำตัวแปรหน่วยความจำกลับสู่สถานะที่เกิดขึ้น (และยังคงเป็นเช่นนี้แม้ว่าสัญญาณจะเปลี่ยนอีกครั้ง)
  3. โปรแกรมแจ้งให้ทราบว่าตัวแปรเปลี่ยนสถานะและย้ายการดำเนินการไปยังฟังก์ชั่นการจัดการ
  4. สิ่งแรกที่ต้องทำเพื่อให้สามารถฟังการขัดจังหวะนี้ได้อีกครั้งคือการรีเซ็ตตัวแปรหน่วยความจำนี้เป็นสถานะที่ไม่เกิดขึ้น

นี่คือความแตกต่างระหว่าง ManualResetEvent และ AutoResetEvent
หาก ManualResetEvent เกิดขึ้นและฉันไม่รีเซ็ตในครั้งต่อไปที่เกิดขึ้นฉันจะไม่สามารถฟังได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.