2011-05-13 5 views
1

특정 작업 (예 : 데이터베이스의 일부 진행 업데이트 또는 데이터베이스에서 실행할 새 작업 확인)을 주기적으로 실행하는 타이머가 필요합니다.대기 핸들을 사용하는 조건부주기 타이머

이러한 작업은 작업을 실행해야하는지 여부를 지정하는 WaitHandle에 바인딩됩니다. 그래서 기본적으로 이것은 AutoResetEvent가 될 수 있습니다. AutoResetEvent는 데이터베이스에 새로운 Entity가있을 때 외부에서 설정되고 이러한 새로운 Entities에 대한 검색을 트리거합니다. 데이터베이스에 쿼리 수를 제한하기 때문에 타이머가 필요합니다. 따라서 10 개의 새로운 알림이 도착하면 AutomaticResetEvent는 한 번만 설정되며이 모든 것에 대해 하나의 쿼리 만있게됩니다.

나의 첫번째 시도는 다음과 같습니다 :이 방법

class ConditionalScheduler 
{ 
    public void AddConditionalAction(WaitHandle handle, Action action) 
    { 
     lock (syncRoot) 
     { 
      handles.Add(handle); 
      actions.Add(handle, action); 
     } 
    } 

    private readonly object syncRoot = new object(); 

    private readonly Dictionary<WaitHandle, Action> actions = new Dictionary<WaitHandle, Action>(); 
    private readonly List<WaitHandle> handles = new List<WaitHandle>(); 

    public void RunTimerLoop() 
    { 
     do 
     { 
      WaitHandle[] waitHandles = handles.ToArray(); 
      int index = WaitHandle.WaitAny(waitHandles); 

      if (index >= 0) 
      { 
       WaitHandle handle = waitHandles[index]; 

       Action action; 
       lock (syncRoot) 
       { 
        action = actions[handle]; 
       } 

       action(); 
      } 
      Thread.Sleep(5000); 
     } while (true); 
    } 

문제는 WaitHandle.WaitAny는 트리거되는 첫 번째 WaitHandle이 저에게 색인을 줄 것입니다. 따라서 두 개 이상의 WaitHandles가 트리거되면 첫 번째 작업 만 실행하고 다른 작업은 실행하지 않습니다.

지정된 기간 내에 트리거 된 모든 작업을 실행하는 데 필요한 결과를 얻으려면 더 좋은 디자인을 갖고 있습니까? 이 문제를 단순화하면 WaitHandles 대신 다른 종류의 알림 메커니즘을 사용할 수 있습니다.

감사합니다.

답변

1

어쩌면 2 스레드 대기열/대량 실행으로 갈 수 있을까요? 코드 다운은 Visual Studio없이 작성한 개념이므로 목록에서 수행하고 있습니다.이 작업은 큐로 수행하는 것이 좋지만 intellisense 없이는 구문을 기억하지 못합니다 :) ...

private readonly Dictionary<WaitHandle, Action> actions = new Dictionary<WaitHandle, Action>(); 
    private readonly List<WaitHandle> handles = new List<WaitHandle>(); 
    private readonly List<WaitHandle> triggeredHandles = new List<WaitHandle>(); 

// thread 1 
    public void CheckLoop() 
    { 
     do 
     { 
      WaitHandle[] waitHandles = handles.ToArray(); 
      int index = WaitHandle.WaitAny(waitHandles); 

      if (index >= 0) 
      { 
       lock (triggeredHandles) 
       { 
        triggeredHandles.Add(waitHandles[index]); 
       } 

      }    
     } while (true); 
    } 

// thread 2 
public void RunLoop() 
    { 
     do 
     { 
      lock(triggeredHandles) 
      { 
       foreach (var th in triggeredHandles) { 

        Action action; 
        lock (syncRoot) 
        { 
         action = actions[th]; 
        } 

        action();     
       } 
       triggeredHandles.Clear(); 
      } 
      Thread.Sleep(5000); 
     } while (true); 
    } 
+0

이것이 효과가있는 것 같습니다. 하지만 난 단지 하나의 스레드와 관련된 솔루션을 기대하고 있었는데 ... 그것은 나를 위해 약간 무거운 것 2 스레드를 사용하여 보인다. – aKzenT

+0

Windows 작업 관리자를 열고 성능 탭으로 이동하여 OS에서 실행중인 스레드 수를 확인하십시오. 지금 832 명이 있습니다. 그래서 나는 하나의 mroe가 그렇게 나쁘지 않을 것이라고 생각한다 : D –

+0

그리고 이것은 하나의 쓰레드에서 수행 될 수있다 : 만일 당신이 큐에 핸들을 추가하고 5000을 기다리지 않는다면, 실행해야 할 X 개 이상의 핸들이 있다면 모두 실행하고 5000 –

0

Reactive Extensions (Rx)을 사용하면 많은 번거 로움을 피할 수 있습니다. 요청하는 방식대로 이벤트를 작성하는 데는 많은 방법이 있습니다.

This site은 rx가 할 수있는 일을 볼 수있는 편리한 방법입니다.

1

내장 된 타이머 클래스를 사용 해본 적이 있습니까? System.Threading.Timer은 관련 이벤트와 더 많은 기능을 제공하는 ThreadPool 또는 System.Timers.Timer을 사용하는 경량 구현입니다.

+0

이것은 실제로 내 문제를 해결하지 못합니다. 나는 주기적으로 행동을 수행하는 법을 안다. 내가 모르는 것은 조건부 행동을 가져 오는 방법입니다. – aKzenT

+0

@aKzenT : 물론, 'Thread.Sleep'은 몇 가지 문제가 있습니다 : 타이밍 감각으로 정확하지 않고 예약되어 있습니다. 쓰레드는하지만 어떤 일을시키지 않으며, 인터럽트 될 수 없다. –

+0

+1, 내 경우에는 정확성이 그다지 중요하지 않지만, 맞습니다 ...이 타이머 클래스에서 내가 싫어하는 것은 ThreadPool에서 실행된다는 것입니다. "진드기"항상 같은 스레드에있을 싶습니다. 타이머 클래스를 사용하여이를 해결하는 방법을 모릅니다. – aKzenT

관련 문제