我的应用程序中有一个事件,它改变了对象的状态,并在10秒后将该状态重置。但是,如果在这10秒内再次触发该事件,该事件不会改变状态,只是将计时器重置为零。
为了使其简洁易懂,以下是我的代码所做的
- 我有一个事件,它安排任务在10秒后运行
- 如果某个特定类型的任务被调度,而另一个请求也来了,那么现有未来任务的"执行时间"就会调整
当前我使用线程中正在操作的"并发队列"来执行此操作
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.Run和/或Task.Delay().ContinuteWith序列重写工作线程。
您当前的MyWorkerThread
代码是一个繁忙的循环。它将CPU核心驱动到100%。你应该听到你的CPU风扇因为这个而旋转。
以下是我如何实现可重置延迟:
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));
}
}
CCD_ 2将恰好在达到CCD_ 3时完成。您可以随时向targetTicks
添加时间,WaitUntilTimeoutAsync()
将进行调整。通过这种方式,您可以将计时器重置为现在加10秒:
targetTicks = Environment.TickCount + (10 * 1000);
既然你有一项任务可以在你需要的时候完成,你就可以在此基础上采取行动:
targetTicks = Environment.TickCount + (10 * 1000); //Initial timer configuration.
await WaitUntilTimeoutAsync();
InvokeMyAction();