即使在处理计时器

时间:2017-10-26 15:05:31

标签: c#

我有一个由其他主线程处理的计时器,但似乎计时器没有被处理,并且即使在那之后回调正在执行。在代码中我连续轮询语音校准状态然后再次重新初始化计时器

这是代码段:

 private void check_voice_call_State_cb(object obj)
 {
      Voice_call_state_timer.Dispose();
      outputdata = SystemUtil.trace_proc(OnlineData.ADB_PATH, "-s " + 
            OnlineData.ADB_serial[PhoneNum] + @" shell ""dumpsys 
            telephony.registry | grep mCallState""");

      Voice_call_state_timer = new System.Threading.Timer(
           check_voice_call_State_cb,
           this, 
           2000,
           System.Threading.Timeout.Infinite); 

    }

1 个答案:

答案 0 :(得分:0)

来自MSDN Documentation for the class

  

当不再需要计时器时,使用Dispose方法释放计时器持有的资源。请注意,在调用Dispose()方法重载之后可能会发生回调,因为定时器会将回调排队以供线程池线程执行。您可以使用Dispose(WaitHandle)方法重载等待所有回调完成。

因此,您需要使用其他重载来等待所有回调完成。

 private void check_voice_call_State_cb(object obj)
 {
      using(var handle = new ManualResetEvent(false))
      {
          var disposed = Voice_call_state_timer.Dispose(handle);
          if(!disposed)
          {
                //This is a extra firing of the event, we should not process further.
                return;
          }
          handle.WaitOne(); //Wait for the dispose to finish here.
      }
      outputdata = SystemUtil.trace_proc(OnlineData.ADB_PATH, "-s " + 
            OnlineData.ADB_serial[PhoneNum] + @" shell ""dumpsys 
            telephony.registry | grep mCallState""");

      Voice_call_state_timer = new System.Threading.Timer(
           check_voice_call_State_cb,
           this, 
           2000,
           System.Threading.Timeout.Infinite); 

}

然而,更好的解决方案是使用标志来检测多个呼叫,然后只需调用Change来设置计时器关闭的新时间。与重复创建和处理计时器相比,这使用的资源要少得多。

 var timerSemaphore = new SemaphoreSlim(1)
 private void check_voice_call_State_cb(object obj)
 {
     var gotLock = timerSemaphore.Wait(0);
     if(!gotLock)
     {
         //Another instance of the timer callback is running, just return.
         return;
     }
     try
     {
         outputdata = SystemUtil.trace_proc(OnlineData.ADB_PATH, "-s " + 
            OnlineData.ADB_serial[PhoneNum] + @" shell ""dumpsys 
            telephony.registry | grep mCallState""");

         //Move this to inside the finally bock to make this happen even on a exception.
         Voice_call_state_timer.Change(2000, System.Threading.Timeout.Infinite); 
     }
     finally
     {
         timerSemaphore.Release();
     }    
}