문제

나는 이것에 대한 문서를 읽었고 나는 이해한다고 생각한다. an AutoResetEvent 코드가 통과하면 재설정됩니다 event.WaitOne(), 그러나 a ManualResetEvent 하지 않습니다.

이 올바른지?

도움이 되었습니까?

해결책

예. 그것은 유료 부스와 문의 차이와 같습니다. 그만큼 ManualResetEvent 문을 닫아야하는 도어입니다 (재설정) 수동으로. 그만큼 AutoResetEvent 유료 부스로, 한 차량이 지나가기 전에 한 대의 자동차가 지나가고 자동으로 닫을 수 있습니다.

다른 팁

그냥 상상해보십시오 AutoResetEvent 실행 WaitOne() 그리고 Reset() 단일 원자 작업으로.

짧은 대답은 예입니다. 가장 중요한 차이점은 autoresetevent가 하나의 대기 스레드 만 계속할 수 있다는 것입니다. 반면에 ManualResetevent는 스레드를 동시에 동시에 동시에 허용하여 멈추라 (재설정)를 지시 할 때까지 계속할 수 있습니다.

C# 3.0 Nutshell Book에서 가져온 Joseph Albahari

C#의 스레딩 - 무료 전자 책

ManualResetevent는 Autoresetevent의 변형입니다. 스레드가 Waitone 호출을 통과 한 후에 자동으로 재설정되지 않으므로 게이트와 같은 기능을 수행합니다. 호출 세트는 게이트를 열어 게이트에서 Waitone을 통과하는 스레드를 허용합니다. 호출 재설정은 게이트를 닫아 잠재적으로 웨이터의 대기열이 다음에 열릴 때까지 축적 될 수 있습니다.

"Spin-Sleeping"과 함께 부울 "GateOpen"필드 (휘발성 키워드로 선언) 로이 기능을 시뮬레이션 할 수 있습니다.

ManualReseteVents는 때때로 특정 작업이 완료되었거나 스레드가 완료된 초기화이며 작업을 수행 할 준비가되었음을 알리는 데 사용됩니다.

이해를 명확히하기 위해 간단한 예제를 만들었습니다 ManualResetEvent vs 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를 상태를 나타내는 방법으로 볼 수 있습니다. 무언가가 켜져 있습니다 (세트) 또는 꺼짐 (재설정). 약간의 지속 시간이 발생합니다. 해당 상태가 발생하기를 기다리는 모든 스레드는 진행될 수 있습니다.

autoresetevent는 신호와 더 비슷합니다. 한 번의 샷은 무슨 일이 일어 났음을 나타냅니다. 지속 시간이없는 발생. 일반적으로 반드시 발생한 "무언가"는 작지만 단일 스레드로 처리해야합니다. 따라서 단일 스레드가 이벤트를 소비 한 후 자동 재설정이 필요합니다.

예, 맞습니다.

이 두 가지를 사용하여 아이디어를 얻을 수 있습니다.

당신이 당신이 어떤 작업을 마치고 다른 (스레드)가 끝났다고 말해야한다면 이제 기다릴 수 있습니다. 이제 ManualResetevent를 사용해야합니다.

모든 리소스에 대한 상호 독점 액세스 권한이 필요한 경우 Autoresetevent를 사용해야합니다.

autoresetevent 메모리에서 부울 변수를 유지합니다. 부울 변수가 False 인 경우 스레드를 차단하고 부울 변수가 참이면 스레드가 차단 해제됩니다.

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

우리는 2 초를 인수로 통과시켜 Waitone 방법을 불렀습니다. while 루프에서는 신호가 2 초 동안 기다린 다음 계속 작동합니다. 스레드가 신호를 얻었을 때 WaitOne은 True를 반환하고 루프를 종료하고 "스레드 GOT 신호"를 인쇄합니다.

방법을 설정합니다

autoresetevent set 메소드는 신호를 대기 스레드로 보냈습니다. 아래는 호출 세트 방법의 구문입니다.

autoResetEvent.Set();

ManualResetevent 메모리에서 부울 변수를 유지합니다. 부울 변수가 False 일 때 모든 스레드를 차단하고 부울 변수가 true하면 모든 스레드를 차단 해제합니다.

ManualResetevent를 인스턴스화하면 기본 부울 값으로 초기화합니다.

ManualResetEvent manualResetEvent = new ManualResetEvent(false);

위의 코드에서는 ManualResetevent를 False 값으로 초기화합니다. 즉, WaitOne 메소드를 호출하는 모든 스레드가 일부 스레드가 SET () 메소드를 호출 할 때까지 차단됩니다.

실제 값으로 ManualResetevent를 초기화하면 WaitOne 메소드를 호출하는 모든 스레드가 차단되지 않고 추가로 진행할 수 없습니다.

Waitone 방법

이 방법은 현재 스레드를 차단하고 다른 스레드에 의해 신호를 기다립니다. 신호를 수신하면 false를 반환하면 true를 반환합니다.

아래는 Waitone 메소드를 호출하는 구문입니다.

manualResetEvent.WaitOne();

Waitone 메소드의 두 번째 과부하에서 현재 스레드가 신호를 기다릴 때까지 시간 간격을 지정할 수 있습니다. 시간 내에 내부에있는 경우 신호를받지 않으면 False를 반환하고 다음 방법 줄로 들어갑니다.

아래는 시간 간격으로 WaitOne 방법을 호출하는 구문입니다.

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

Waitone 방법으로 5 초를 지정했습니다. ManualReseteVent 객체가 5 초 사이에 신호를받지 않으면 issignalled 변수를 False로 설정합니다.

방법을 설정합니다

이 방법은 신호를 모든 대기 스레드로 보내는 데 사용됩니다. set () 메소드 SET MANUALRESETEVENT 객체 부울 변수를 true로 설정합니다. 모든 대기 스레드가 차단 해제되어 더 진행됩니다.

아래는 Calling Set () 메소드의 구문입니다.

manualResetEvent.Set();

방법을 재설정하십시오

ManualResetevent 객체에서 set () 메소드를 호출하면 부울은 사실입니다. reset () 메소드를 사용할 수있는 값을 재설정하려면. 재설정 메소드 부울 값을 False로 변경합니다.

아래는 호출 재설정 방법의 구문입니다.

manualResetEvent.Reset();

스레드에 여러 번 신호를 보내려면 세트 메소드를 호출 한 후 즉시 재설정 메소드를 호출해야합니다.

Autoresetevent 및 ManualResetevent를 이해하려면 스레딩이 아니라 인터럽트를 이해해야합니다!

.NET은 가장 멀리 떨어진 저수준 프로그래밍을 초래하려고합니다.

인터럽트는 낮은 수준의 프로그래밍에 사용되는 것입니다. 이는 로우가 높아 졌다는 신호와 동일합니다 (또는 그 반대로). 이런 일이 발생하면 프로그램이 일반 실행을 방해하고 실행 포인터를이를 처리하는 기능으로 이동합니다. 이벤트.

인터럽트가 일어 났을 때 가장 먼저해야 할 일은 초기화 그 상태, Becosa Hardware는 다음과 같은 방식으로 작동합니다.

  1. 핀은 신호에 연결되고 하드웨어가 변경 될 수 있습니다 (신호는 두 개의 상태 만 가질 수 있음).
  2. 신호가 변경되면 어떤 일이 발생하고 하드웨어가 메모리 변수 상태에 일어났다 (그리고 신호가 다시 변경 되더라도 이와 같이 남아있다).
  3. 이 프로그램은 가변적 인 변화가 상태를 변경하고 실행을 처리 함수로 옮깁니다.
  4. 여기서 가장 먼저해야 할 일은이 인터럽트를 다시들을 수있는 것입니다. 초기화 이 메모리는 상태에 대한 변수입니다.

이것은 ManualResetevent와 Autoresetevent의 차이입니다.
ManualResetevent가 발생하고 재설정되지 않으면 다음에 발생하면들을 수 없습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top