2010-05-12 2 views
5

C#/.NET에서 ManualResetEvent 및 AutoResetEvent 클래스를 사용하는 것에 대한 간단한 대안을 작성했습니다. 이 문제의 배경은 커널 잠금 객체를 사용하지 않고도 이벤트와 같은 기능을 사용하는 것이 었습니다.C#의 Manual/AutoResetEvent에 대한 간단한 대안

비록 코드가 테스트와 제작 모두에서 잘 작동하는 것으로 보이지만, 모든 가능성에 맞는 이런 종류의 것을 얻는 것은 복잡한 일이 될 수 있으며, 나는 StackOverflow 군중으로부터 어떤 건설적인 의견이나 비판을 겸허하게 요청할 것입니다. 잘하면 (검토 후) 이것은 다른 사람들에게 유용 할 것입니다.

사용법은 Set()에 사용되는 Notify()가있는 Manual/AutoResetEvent 클래스와 비슷해야합니다.

여기 간다 : 이것은 Win32에서 이벤트가 비싸다는 가정에서 작동

using System; 
using System.Threading; 

public class Signal 
{ 
    private readonly object _lock = new object(); 
    private readonly bool _autoResetSignal; 
    private bool _notified; 

    public Signal() 
    : this(false, false) 
    { 
    } 

    public Signal(bool initialState, bool autoReset) 
    { 
    _autoResetSignal = autoReset; 
    _notified = initialState; 
    } 

    public virtual void Notify() 
    { 
    lock (_lock) 
    { 
     // first time? 
     if (!_notified) 
     { 
     // set the flag 
     _notified = true; 

     // unblock a thread which is waiting on this signal 
     Monitor.Pulse(_lock); 
     } 
    } 
    } 

    public void Wait() 
    { 
    Wait(Timeout.Infinite); 
    } 

    public virtual bool Wait(int milliseconds) 
    { 
    lock (_lock) 
    { 
     bool ret = true; 
     // this check needs to be inside the lock otherwise you can get nailed 
     // with a race condition where the notify thread sets the flag AFTER 
     // the waiting thread has checked it and acquires the lock and does the 
     // pulse before the Monitor.Wait below - when this happens the caller 
     // will wait forever as he "just missed" the only pulse which is ever 
     // going to happen 
     if (!_notified) 
     { 
     ret = Monitor.Wait(_lock, milliseconds); 
     } 

     if (_autoResetSignal) 
     { 
     _notified = false; 
     } 
     return (ret); 
    } 
    } 
} 
+1

당신은으로 ManualResetEvent/AutoResetEvents을 사용하여에이를 ​​벤치마킹 적이 있습니까? 성능 차이는 얼마나 중요한가? – James

+0

아니요 아직 주요 목표가 이벤트 객체를 사용하여 커널이 아닌 핸들/리소스를 만드는 것이 아니므로 아직하지 않았습니다. 나는 몇몇 시험을 설치하는 것을 시도 할 것이다, 감사합니다. – sweetlilmre

+1

스레딩 프리미티브를 구현하는 것은 고유 한 암호화 알고리즘을 구현하는 것과 같습니다. 당신이 도메인의 전문가가 아니라면, 당신은 그것을 망칠 것입니다. 당신이 * 전문가 * 일지라도, 당신은 아직도 그것을 망칠지도 모른다. 하지 마. .NET 4에는 이미 "경량"버전 인'ManualResetEventSlim'과 관련 클래스가 있습니다. – Aaronaught

답변

4

합니다. 그들은 내가 생각할 수있는 것이 거의 없다. 그것은 사건보다 비용이 적다. 이것이 중요한 이유는 .NET 디자이너가 Win32 이벤트를 사용하여 MRE와 ARE를 구현하는 것이 좋은 아이디어라고 판단하는 것입니다.

교체 비용은 스레딩 경주가 발생했을 때 경험하게 될 주요 FUD이며 원인을 알지 못합니다.

+1

음, ARE와 MRE가 모니터보다 비싸지 만 커널 내부에서 이벤트를 사용한다고 가정합니다. 나는 틀린 입증되고 싶을 것이다 :) – sweetlilmre

+0

이 기사는 빠른 것에 의하여 마이크로 소프트 세부 사항에 의하여이다 : http://msdn.microsoft.com/en-us/library/ms228964.aspx –

+0

.NET의 커널 모드 전환 관점에서 Win32 이벤트는 비싸므로 위의 @Aaronaught 대답에 따라 .NET 4의 경량 추가가 필요합니다. – sweetlilmre

1

불행히도, 올바른 모니터 구현은 Win32 동기화 프리미티브를 감안할 때 상당히 비중 있습니다. 나의 초기 의심은 "잠금"이 이벤트보다 리소스 사용이 더 많을 것이라는 것이다.

+0

나는 잠금 장치가 이벤트 내부에서 결코 구현되지 않는다고 확신한다. IIRC에는 스레드 잠금을 처리하고 이벤트보다 가벼운 특수 스레드 구조가 있습니다. – sweetlilmre

+0

@sweetlilmre - Rotor/SharedCCI 구현을 살펴본 결과 일부 스핀 록 스타일 잠금을 사용하지만 필요한 경우 호스트가 제공 한 이벤트 유형으로 내려갑니다. –

+0

예, 자체 스핀 블록 비트를 사용하여 스핀합니다. 내가 grokked하지 않은 한 가지는 그들이 Windows 스케줄러 알려주는 방법입니다. 코드 위치를 얻었습니까? –

1

AutoResetEvent의 성능을 최적화하는 한 가지 방법은 자신의 변수에 상태 (신호 또는 비 신호)를 유지하는 것입니다. 따라서 커널로 이동하여 실제로 이벤트 객체를 사용하기 전에 응용 프로그램의 상태를 확인할 수 있습니다 변수를 사용하고 전체 시간 동안 사용자 모드로 유지하십시오.
몇 달 전에이 개념의 demonstration을 게시했습니다.