2011-05-06 3 views
1

데이터를 지속적으로 처리하는 서비스가 있고 메시징을 통해 새 데이터를 처리하라는 요청을받습니다. 처리량이 많으면 새로운 요청이 병합되어 한꺼번에 처리됩니다. AutoResetEvent는 새 요청을 사용할 수 있음을 프로세서에 알리는 데 사용됩니다.AutoResetEvent를 사용하여 작업자 스레드에 신호 보내기

WaitOne 이후 currentRequest가 null이 될 수 있으면 제 질문은 EventLoop에 있습니까?

_eventAvailable.Set()을 잠금 (_eventLocker) 외부에 두는 것은 나쁜 습관입니까? WaitOne에서 시작하지 않고 즉시 잠금 장치 (_eventLocker)에 컨테스트를하지 않도록 이동했습니다.

다음 코드를 더 잘 작성하는 방법에 대한 제안 사항이 있으십니까?

public sealed class RealtimeRunner : MarshalByRefObject 
{ 
    /// <summary> 
    /// The actual event, new events get merged into this if it is not null 
    /// </summary> 
    private Request _pendingRequest; 

    /// <summary> 
    /// Used to signal the runner thread when an event is available to process 
    /// </summary> 
    private readonly AutoResetEvent _eventAvailable = new AutoResetEvent(false); 
    private readonly object _eventLocker = new object(); 


    /// <summary> 
    /// Called on a background thread via messaging 
    /// </summary> 
    public void QueueEvent(RealtimeProcessorMessage newRequest) 
    { 
     bool mergedRequest; 
     lock (_eventLocker) 
     { 
      if (_pendingRequest == null) 
      { 
       mergedRequest = false; 
       _pendingRequest = new Request(newRequest, _engine); 
      } 
      else 
      { 
       mergedRequest = true; 
       _pendingRequest.Merge(newRequest, _engine); 
      } 
     } 

     _eventAvailable.Set(); 
    } 


    /// <summary> 
    /// This is running on its own thread 
    /// </summary> 
    private void EventLoop() 
    { 
     while (true) 
     { 
      // Block until something exists in _pendingRequest 
      _eventAvailable.WaitOne(); 

      Request currentRequest; 
      lock (_eventLocker) 
      { 
       currentRequest = _pendingRequest; 
       _pendingRequest = null; 
      } 

      // CAN THIS EVER BE NULL? 
      if (currentRequest == null) 
       continue; 

      //do stuff with the currentRequest here 
     } 
    } 
} 

답변

1

예, if (currrentRequest == null)은 true로 평가 될 수 있습니다. 경주하는 두 개의 스레드가 _eventAvailable.Set()을 호출하는 것을 고려하십시오. 하나는 통화를 완료하고 다른 하나는 선매로 처리됩니다. 한편 EventLoop 스레드는 깨어나 루프의 전체 반복을 완료합니다. 이제 _pendingRequest이 null이고 WaitHandle이 다시 신호를 받기를 기다리는 상황이 발생했습니다.

전적으로 다른 해결책을 제시하고자합니다. 생산자 - 소비자 패턴을 사용하여 코드를 간소화 할 수 있습니다. 이 패턴은 블로킹 큐를 사용하여 가장 쉽게 구현됩니다. BlockingCollection 클래스는 이러한 대기열을 구현합니다.

+0

감사합니다. 제작자 소비자를 살펴 봤지만 여러 요청을 단일 요청으로 병합 할 수 있기 때문에 좀 더 수동적 인 접근 방법을 원했습니다. 내 서비스 처리에는 30 초가 걸릴 수 있으며 요청은 초당 여러 번 올 수 있습니다. TryTake를 반복 사용하여 소비자 측에서 이들을 병합 할 수 있다고 생각하십니까? 그래서 하나의 m_Queue.Take() 호출이있을 것입니다 (m_Queue.TryTake())? – BrandonAGr

+0

@BrandonAGr : 물론입니다. 'Take '를 호출하여 초기 요청을 얻은 직후에'TryTake'를 호출하는 또 다른 루프를 돌면서 몇 가지 요청을 신속하게 선택할 수 있습니다. 여기에는 많은 가능성이 있습니다. 그러나 대기열이 비어있을 때 블로킹 효과를 발생 시키려면 여전히 'Take'를 호출해야합니다. –

관련 문제