나는 이것에 관한 문서를 읽었으며 이해한다고 생각합니다. AutoResetEvent
재설정 코드를 통과 할 때 event.WaitOne()
,하지만은 ManualResetEvent
않습니다.
이 올바른지?
나는 이것에 관한 문서를 읽었으며 이해한다고 생각합니다. AutoResetEvent
재설정 코드를 통과 할 때 event.WaitOne()
,하지만은 ManualResetEvent
않습니다.
이 올바른지?
답변:
예. 그것은 tollbooth와 문의 차이점과 같습니다. 는 ManualResetEvent
수동 (리셋)을 폐쇄 할 필요가 문이다. 이것은 AutoResetEvent
유료 자동차이며, 한 자동차가 지나가고 다음 자동차가 통과하기 전에 자동으로 닫힙니다.
그냥 상상이 AutoResetEvent
가 실행 WaitOne()
및 Reset()
단일 원자 작업으로.
Joseph Albahari가 작성한 C # 3.0 간단히보기
ManualResetEvent는 AutoResetEvent의 변형입니다. 스레드가 WaitOne 호출에서 통과 된 후에 자동으로 재설정되지 않는다는 점이 다릅니다. 따라서 게이트와 같은 기능을합니다. 호출 Set은 게이트를 열어 게이트에서 WaitOne이 통과하는 스레드 수를 허용합니다. Reset을 호출하면 게이트가 닫히고 다음에 열 때까지 웨이터 큐가 누적 될 수 있습니다.
"스핀 슬리핑 (spin-sleeping)"과 함께 부울 "gateOpen"필드 (휘발성 키워드로 선언)를 사용하여이 기능을 시뮬레이션 할 수 있습니다. 플래그를 반복해서 확인한 다음 짧은 시간 동안 슬리핑합니다.
ManualResetEvents는 특정 작업이 완료되었거나 스레드의 초기화가 완료되어 작업을 수행 할 준비가되었음을 나타내는 데 사용됩니다.
ManualResetEvent
vs의 이해를 명확히하기 위해 간단한 예제를 만들었습니다 AutoResetEvent
.
AutoResetEvent
: 3 개의 작업자 스레드가 있다고 가정합니다. 해당 스레드 중 하나라도 호출 WaitOne()
하면 다른 두 스레드가 모두 실행을 중지하고 신호를 기다립니다. 나는 그들이 사용하고 있다고 가정 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);
}
}
}
자동 리셋 이벤트
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);
}
}
}
AutoResetEvent 는 메모리에 부울 변수를 유지합니다. 부울 변수가 false이면 스레드를 차단하고 부울 변수가 true이면 스레드를 차단 해제합니다.
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를 리턴하고 루프를 종료하고 "Thread got signal"을 인쇄합니다.
방법 설정
AutoResetEvent Set 메소드는 작업을 진행하기 위해 대기 스레드에 신호를 보냈습니다. 다음은 Set 메소드를 호출하는 구문입니다.
autoResetEvent.Set();
ManualResetEvent 는 메모리에 부울 변수를 유지합니다. 부울 변수가 false이면 모든 스레드를 차단하고 부울 변수가 true이면 모든 스레드를 차단 해제합니다.
ManualResetEvent를 인스턴스화 할 때 기본 부울 값으로 초기화합니다.
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
위의 코드에서 ManualResetEvent를 false 값으로 초기화합니다. 즉, 일부 스레드가 Set () 메서드를 호출 할 때까지 WaitOne 메서드를 호출하는 모든 스레드가 차단됩니다.
ManualResetEvent를 true 값으로 초기화하면 WaitOne 메소드를 호출하는 모든 스레드가 차단되지 않고 계속 진행할 수 있습니다.
WaitOne 방법
이 메소드는 현재 스레드를 차단하고 다른 스레드의 신호를 기다립니다. 신호를 받으면 true를, 그렇지 않으면 false를 반환합니다.
다음은 WaitOne 메소드를 호출하는 구문입니다.
manualResetEvent.WaitOne();
WaitOne 메소드의 두 번째 과부하에서는 현재 스레드가 신호를 기다릴 때까지의 시간 간격을 지정할 수 있습니다. 내부 시간 내에 신호를받지 못하면 false를 반환하고 다음 메소드 행으로 이동합니다.
다음은 시간 간격으로 WaitOne 메소드를 호출하는 구문입니다.
bool isSignalled = manualResetEvent.WaitOne(TimeSpan.FromSeconds(5));
WaitOne 메서드에 5 초를 지정했습니다. manualResetEvent 객체가 5 초 사이에 신호를받지 못하면 isSignalled 변수를 false로 설정합니다.
방법 설정
이 방법은 모든 대기 스레드에 신호를 보내는 데 사용됩니다. Set () 메서드는 ManualResetEvent 객체 부울 변수를 true로 설정합니다. 대기중인 모든 스레드가 차단 해제되고 계속 진행됩니다.
다음은 Set () 메서드를 호출하는 구문입니다.
manualResetEvent.Set();
리셋 방법
ManualResetEvent 객체에서 Set () 메서드를 호출하면 부울 값은 true로 유지됩니다. 값을 재설정하기 위해 Reset () 메소드를 사용할 수 있습니다. 재설정 방법은 부울 값을 false로 변경합니다.
다음은 Reset 메소드를 호출하는 구문입니다.
manualResetEvent.Reset();
스레드에 신호를 여러 번 보내려면 Set 메서드를 호출 한 후 즉시 Reset 메서드를 호출해야합니다.
AutoResetEvent 및 ManualResetEvent를 이해하려면 스레딩이 아니라 인터럽트를 이해해야합니다!
.NET은 저수준 프로그래밍을 가능한 한 멀리 활용하기를 원합니다.
인터럽트는 로우 레벨 프로그래밍에서 사용되는 것으로 로우에서 하이로 상승했다는 신호와 같습니다. 이 경우 프로그램은 정상적인 실행을 중단하고 실행 포인터를이 이벤트 를 처리하는 함수로 이동하십시오 .
인터럽트가 발생할 때 가장 먼저해야 할 일은 하드웨어가 이런 식으로 작동하기 때문에 상태 를 재설정 하는 것입니다.
이것이 ManualResetEvent와 AutoResetEvent의 차이점입니다.
ManualResetEvent가 발생하고 재설정하지 않으면 다음에 발생하면들을 수 없습니다.