2016-06-09 3 views
1

응용 프로그램에 개체의 상태가 변경되고 해당 상태가 10 초 후에 재설정되도록하는 이벤트가 있습니다. 그러나 해당 이벤트가 10 초 이내에 다시 시작되면 이벤트는 상태를 변경하지 않고 단순히 타이머를 0으로 재설정합니다.작업을 사용하여 지연된 "타이머 스타일"작업 수행

것은 이해하기가 간결하고 쉽게하기 위해, 여기 내 코드는

  1. 내가 스케줄 작업을 10 초 후에 특정 유형의
  2. 만약 하나의 작업을 실행 할 수있는 이벤트를 가지고 무엇을 가 예정되어 있고 또 다른 요청이 들어 오면 기존의 미래 작업에 대한 "실행 시간"이 조정됩니다.

현재 나는 'ConcurrentQueue'

public class ToDo 
{ 
public DateTime Expires { get; set; } 
public Action StuffToDo { get; set; } 
} 

그런 다음 스레드에서 조작되고 내 스레드 여기

public void MyWorkerThread(object parameters) 
{ 
while (!<check if cancellation requested>) 
{ 
    ToDo stuff; 
    if (myConcurrentQueue.TryDequeue(out stuff)) 
    { 
    if (DateTime.Now > stuff.Expires) 
     { 
     Task.StuffToDo.Invoke(); 
     } 
    else 
     { 
     // queue it back if it is not time to execute it 
     // 
     myConcurrentQueue.Enqueue(stuff); 
     } 
    } 
} 
} 

를 사용하여 그 일을하고 작업

private ConcurrentDictionary<ToDo> _todoDictionary = new ConcurrentDictionary<ToDo>(); 
private ConcurrentQueue<ToDo> myConcurrentQueue = new ConcurrentQueue<ToDo>(); 
public void MyEventFired(MyEventArgs e) 
{ 
ToDo todo = null; 

if (_todoDictionary.ContainsKey(e.TaskType)) 
{ 
    _todoDictionary.TryRemove(out todo); 
    if (DateTime.Now >= task.Expires) 
    { 
    todo = new ToDo(); 
    todo.StuffToDo = new Action(() => { /* stuff here */ }); 
    } 
} 
else 
{ 
    todo = new ToDo(); 
    todo.StuffToDo = new Action(() => { /* stuff here */ }); 
} 

todo.Expires = DateTime.Now + TimeSpan.FromSeconds(10.0); 

_todoDictionary.Add(e.TaskType, todo); 
myConcurrentQueue.Enqueue(todo); 
} 
를 큐에 내 이벤트 핸들러입니다

누군가 내게 암시한다고 TPL을 사용하여 위의 모든 작업을 수행하면 작업자 스레드가 필요하지 않으며 'Task.Delay'만 사용할 수 있습니다. 나는 아직도 내가 그것에 접근 할 방법을 고민하고있다. 어떤 아이디어라도 감사 할 것입니다. 여기

내가 내가 Task.Run 및/또는 Task.Delay(). ContinueWith 시퀀스의 측면에서 작업자 스레드를 다시 찾고 있어요하고 싶은 것입니다.

+0

포스트 무엇을 당신이 어떻게하려고했는지가 아니라,하고 싶습니다. Reactive Extensions에는 이미 타이머, 윈도우 등이 있습니다. TPL Dataflow에는 이미 델리게이트가 처리 할 수있는 메시지 큐가 있으며 지연이 포함될 수 있습니다. 아니면'for (;;) {...; someMethod (someData)를 기다린다. 작업을 기다리고 있습니다. Delay (10000);} –

+0

@PanagiotisKanavos TPL을 사용하여 코드를 다시 작성하고 싶습니다. 제 질문이 충분히 분명한 게 아니라면 사과하십시오. 나는 편집 할 것이다. – fahadash

+0

하지만 * 달성하고자하는 것은 무엇입니까? 10 초마다 하나의 메시지 만 처리합니까? 메시지를 10 초 동안 지연 시키시겠습니까? 한 번에 10 초 간격으로받은 모든 메시지를 처리 ​​하시겠습니까? 10 초 창 안의 * one * 메시지 만 처리 하시겠습니까? –

답변

1

현재 MyWorkerThread 코드는 바쁜 회전 루프입니다. 그것은 CPU 코어에서 100 %까지 운전합니다. 이 때문에 CPU 팬이 회전하는 소리가 들려야합니다. 여기

내가 재설정 지연을 구현하는 것입니다 방법은 다음과 같습니다 targetTicks에 도달하면

volatile int targetTicks = Environment.TickCount + (10 * 1000); 

async Task WaitUntilTargetReachedAsync() { 
while (true) { 
    var currentTicks = Environment.TickCount; //stabilize value 
    var targetTicksLocal = targetTicks; //volatile read, stabilize value 
    if (currentTicks >= targetTicksLocal) break; //Target reached. 
    await Task.Delay(TimeSpan.FromMilliseconds(targetTicksLocal - currentTicks)); 
} 
} 

WaitUntilTimeoutAsync() 정확히 완료됩니다. 언제든지 targetTicks에 시간을 추가 할 수 있으며 WaitUntilTimeoutAsync()이 조정됩니다. 지금 플러스 10 초 타이머를 재설정 할 수 있습니다이 방법 : 이제 당신은 당신이 당신의 행동을 기반으로 할 수 그것을 필요로 할 때 정확히 완료 작업이 있는지

targetTicks = Environment.TickCount + (10 * 1000); 

:

targetTicks = Environment.TickCount + (10 * 1000); //Initial timer configuration. 
await WaitUntilTimeoutAsync(); 
InvokeMyAction(); 
+0

targetTicks의 조작은 스레드로부터 안전합니까? – fahadash

+0

아니, 나는 그것을 버렸다. 당신은 그것에 대한 자물쇠를 사용할 수 있습니다. 또한 '휘발성'으로 표시 할 수 있습니다. 그러나 그것은 이해하기가 더 어렵고 그것이 옳다는 결론을 내립니다. – usr

관련 문제