使用任务执行延迟"计时器式"操作

时间:2016-06-09 12:23:18

标签: c# multithreading

我的应用程序中有一个事件会改变对象的状态,并在10秒后将该状态指定为重置状态。但是如果该事件在那10秒内再次触发,则事件不会改变状态,只是将计时器重置为零。

为了简洁易懂,以下是我的代码

  1. 我有一个事件,安排要在10秒后运行的任务
  2. 如果某个特定类型的任务被安排,并且另一个任务请求进入,那么"执行时间"对现有的未来任务进行了调整。
  3. 目前我正在使用' 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完成上述所有操作,而且我不需要工作线程,我可以使用&#39; Task.Delay&#39;。我还在考虑如何处理它。任何想法将不胜感激。

    这就是我想要做的事情 我希望用Task.Run和/或Task.Delay()重写工作线程。继续使用序列。

1 个答案:

答案 0 :(得分:1)

您当前的root代码是一个忙碌的旋转循环。它在CPU核心上驱动到100%。你应该听到你的CPU风扇因此而旋转。

以下是我实现可重置延迟的方法:

MyWorkerThread

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添加时间,并targetTicks进行调整。这样您就可以将计时器重置为现在加10秒:

WaitUntilTimeoutAsync()

现在您的任务完全在您需要的时候完成,您可以根据以下内容进行操作:

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