나는 이것에 관한 문서를 읽었으며 이해한다고 생각합니다. AutoResetEvent
재설정 코드를 통과 할 때 event.WaitOne()
,하지만은 ManualResetEvent
않습니다.
이 올바른지?
답변
예. 그것은 tollbooth와 문의 차이점과 같습니다. 는 ManualResetEvent
수동 (리셋)을 폐쇄 할 필요가 문이다. 이것은 AutoResetEvent
유료 자동차이며, 한 자동차가 지나가고 다음 자동차가 통과하기 전에 자동으로 닫힙니다.
답변
그냥 상상이 AutoResetEvent
가 실행 WaitOne()
및 Reset()
단일 원자 작업으로.
답변
짧은 대답은 그렇습니다. 가장 중요한 차이점은 AutoResetEvent는 하나의 단일 대기 스레드 만 계속할 수 있다는 것입니다. 반면에 ManualResetEvent는 스레드가 중지하도록 지시 할 때까지 (다시 설정) 계속할 수 있도록합니다.
답변
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);
}
}
}