2010-07-22 4 views
3

사용하려는 System.Timers.Timer 개체가 있지만 Timer에 연결된 처리를 높은 우선 순위의 스레드에 정상적으로 간섭하지 않으려합니다. 다른 말로하면 나는 아무 것도 실행하지 않는 한 X를 5 초마다 처리하려고한다고 말하고 싶습니다..Timer Elapsed 이벤트는 High Priority 스레드와 어떻게 경쟁합니까?

Timer 작업이 우선 순위가 낮은 방식으로 실행되도록하려면 어떻게해야합니까?

답변

2

System.Timers.Timer에 대한 좋은 점은 SynchronizingObject 속성을 통해 동기화 객체를 할당 한 다음이 객체를 악용하여 Elapsed 이벤트를 실행하여 우선 순위를 제어 할 수 있다는 것입니다.

타이머의 SynchronizingObject 속성에 ElapsedEventReceiver의 인스턴스를 할당하기 만하면됩니다.

면책 조항 : 나는 이것을 아주 빨리 처리 했으므로 마무리 작업을 추가해야 더욱 강력 해졌습니다.

public class ElapsedEventReceiver : ISynchronizeInvoke 
{ 
    private Thread m_Thread; 
    private BlockingCollection<Message> m_Queue = new BlockingCollection<Message>(); 

    public ElapsedEventReceiver() 
    { 
     m_Thread = new Thread(Run); 
     m_Thread.Priority = ThreadPriority.BelowNormal; 
     m_Thread.IsBackground = true; 
     m_Thread.Start(); 
    } 

    private void Run() 
    { 
     while (true) 
     { 
      Message message = m_Queue.Take(); 
      message.Return = message.Method.DynamicInvoke(message.Args); 
      message.Finished.Set(); 
     } 
    } 

    public IAsyncResult BeginInvoke(Delegate method, object[] args) 
    { 
     Message message = new Message(); 
     message.Method = method; 
     message.Args = args; 
     m_Queue.Add(message); 
     return message; 
    } 

    public object EndInvoke(IAsyncResult result) 
    { 
     Message message = result as Message; 
     if (message != null) 
     { 
      message.Finished.WaitOne(); 
      return message.Return; 
     } 
     throw new ArgumentException("result"); 
    } 

    public object Invoke(Delegate method, object[] args) 
    { 
     Message message = new Message(); 
     message.Method = method; 
     message.Args = args; 
     m_Queue.Add(message); 
     message.Finished.WaitOne(); 
     return message.Return; 
    } 

    public bool InvokeRequired 
    { 
     get { return Thread.CurrentThread != m_Thread; } 
    } 

    private class Message : IAsyncResult 
    { 
     public Delegate Method; 
     public object[] Args; 
     public object Return; 
     public object State; 
     public ManualResetEvent Finished = new ManualResetEvent(false); 

     public object AsyncState 
     { 
      get { return State; } 
     } 

     public WaitHandle AsyncWaitHandle 
     { 
      get { return Finished; } 
     } 

     public bool CompletedSynchronously 
     { 
      get { return false; } 
     } 

     public bool IsCompleted 
     { 
      get { return Finished.WaitOne(0); } 
     } 
    } 
} 
+0

이 대답이 주소 지정없이 가정하는 중요한 정보 중 하나는 Windows에서 우선 순위가 더 높은 스레드를 실행할 수있는 한 (일반적으로) 더 낮은 우선 순위의 스레드가 실행되도록 예약되지 않는다는 사실입니다. 즉, 스레드의 priorty를 설정하면 원하는 것을 얻을 수 있습니다. 이 사실은 일부 사람들이 타임리스트의 크기 또는 다른 스키마 만 조정한다고 가정 할 수도 있기 때문에 분명하지 않을 수 있습니다. Windows는 잠시 동안 실행되지 않는 경우 우선 순위가 낮은 스레드를 "굶주 리지"않겠지 만 실제로는 문제가되지는 않습니다. –

+0

@ 제프리 : 좋은 지적입니다. 실 제로는 현재 예제에서 실제로 문제가 될 수 있습니다. 왜냐하면 실행을 위해 정렬 된 메시지가 대기열을 쌓아 쌓기 시작할 것이기 때문입니다. 나는 기회가있을 때 이것을 수정하려고 노력할 것이다. –

1

아마도 가장 쉬운 방법은 '사용중'플래그 (또는 카운트)를 사용하는 것이고 0이 아닌 한 타이머 틱을 무시하는 것입니다.

P. 스레드 우선 순위 변경은 권장되지 않습니다. 거의 필요하지 않습니다.

+0

내 응용 프로그램이 서버의 다른 응용 프로그램에 영향을 미치지 않는지 확인하십시오. 나는 프로파일 링 애플리케이션을 작성하고있다. –

+1

다른 응용 프로그램의 스레드 우선 순위를 변경하는 것은 비현실적 일 수 있지만 자신의 응용 프로그램 우선 순위를 낮추는 것은 거의 불가능합니다. @Michael Hedgpeth - 그러나 프로파일 링 응용 프로그램은 아마도 반대 사례입니다! –

+0

@ 제프리 : 나는 동의하지 않는다. 스레드의 정확한 우선 순위는 반 직관적이며 동적 우선 순위가 Windows 스케줄러에 내장되어 있기 때문에 스레드 우선 순위를 수동으로 조정하면 종종 비생산적입니다. –