定时器方法虽然完成了它的任务,但它并没有停止执行

Posted

技术标签:

【中文标题】定时器方法虽然完成了它的任务,但它并没有停止执行【英文标题】:Timer Method does not stop execution though it finishes its task 【发布时间】:2019-12-12 06:16:19 【问题描述】:

我有一个 Windows 服务,它应该每 5 秒轮询一次数据库以获取新条目并更新日志文件。

我正在使用 System.Timers.Timer 类来调用我的数据库方法并每 5 秒调用一次自动取消。

 protected override void OnStart(string[] args)
 
     try
     
            ServiceLogFile("Service is started at " + DateTime.Now);
            timer.Elapsed += new ElapsedEventHandler(Autocancellation);
            timer.Interval = Int32.Parse(ConfigurationManager.AppSettings["tracktime"]); //number in miliseconds 
            timer.Enabled = true;
      
      catch(Exception ex)
      
           ServiceLogFile("Error in OnStart :" + ex.ToString());
      
  

  public void Autocancellation(object source, ElapsedEventArgs e)
  
        try
        
            lock (this)
            

                //Database accesss
                //select statement 

                //Adding to Data table 
                if(dt.Rows.Count>0)
                
                    //Update Statements 
                
                else
                
                     ServiceLogFile("There is no orders in the table Thread id :" +Thread.CurrentThread.ManagedThreadId);
                 
              
       
   

自动取消方法将具有数据库访问和更新语句。

预期工作流程 -

它应该更新数据库中的所有条目并返回到 onStart 方法并每 5 秒轮询一次。

问题 -

每当它完成更新行并且如果它有时间(例如,如果它在最后一次迭代中在 2 分钟内完成更新语句)并且剩余 3 分钟,它将打印“表中没有订单”。在它完成整个计时器之前,我无法停止打印它。

我尝试停止计时器 - 但这导致它永远不会从 onStart 方法再次轮询数据库。

这里是日志示例

更新开始时 -

Service is stopped at 8/4/2019 1:34:15 PM
Service is started at 8/4/2019 1:34:28 PM
Database check :8/4/2019 1:34:33 PM
INFO Cancelled Order AccessionID : A1
INFO Cancelled Order AccessionID : A2
INFO Cancelled Order AccessionID : A3

迭代结束 -

INFO Cancelled Order AccessionID : A49997
INFO Cancelled Order AccessionID : A49998
INFO Cancelled Order AccessionID : A49999
INFO Cancelled Order AccessionID : A50000
Database check :8/4/2019 1:51:53 PM
There is no orders in the table Thread id :4
Database check :8/4/2019 1:51:53 PM
There is no orders in the table Thread id :3
Database check :8/4/2019 1:51:53 PM
There is no orders in the table Thread id :7

如果我们可以看到上面的日志,它会以相同的方法循环以不打印任何记录。我尝试杀死线程和返回语句。没有任何效果。

经过此迭代时间(5 秒) 这将返回到 onStart 并正确轮询 5 秒,并且日志完美 -

Database check :8/4/2019 1:52:04 PM
There is no orders in the table Thread id :96
Database check :8/4/2019 1:52:09 PM
There is no orders in the table Thread id :97
Database check :8/4/2019 1:52:14 PM

帮助停止正在运行的实例的计时器,它应该按预期进行轮询。

【问题讨论】:

那么为什么你有 else 语句。为什么不处理您的更新并在最后写入日志文件? 因为如果更新语句中有任何中断,我应该在每次迭代的日志文件中打印它。让我们假设如果数据库没有要更新的新行,我需要打印 else 语句。我的问题是在每次更新执行后中断方法执行。 修改DataTable时是否使用同一个锁? 是的@TheodorZoulias 【参考方案1】:

我会将AutoReset 属性设置为False,并在没有更多记录后重新启动计时器。原因是在您忙于处理记录时,您的 Autocancellation 可能会从不同的线程多次调用。

来自MSDN:

获取或设置一个布尔值,指示计时器是否应该提高 仅发生一次 (false) 或重复 (true) 的已用事件。

protected override void OnStart(string[] args)
 
     try
     
            ServiceLogFile("Service is started at " + DateTime.Now);
            timer.AutoReset = false;
            timer.Elapsed += new ElapsedEventHandler(Autocancellation);
            timer.Interval = Int32.Parse(ConfigurationManager.AppSettings["tracktime"]); //number in miliseconds 
            timer.Enabled = true;
            timer.Start();
      
      catch(Exception ex)
      
           ServiceLogFile("Error in OnStart :" + ex.ToString());
      
  

public void Autocancellation(object source, ElapsedEventArgs e)


    try
    
        lock (this)
        

            //Database accesss
            //select statement 

            //Adding to Data table 
            if(dt.Rows.Count>0)
            
                //Update Statements 
            
            else
            

                 ServiceLogFile("There is no orders in the table Thread id :" +Thread.CurrentThread.ManagedThreadId);
             
          
   
   finally
   
// in anycase, start the timer again. In this pattern, you will not get
// any calls until the processing is finished.    
            timer.Start();
       
    

【讨论】:

因此您需要始终执行计时器以检查新数据。因此,在这种情况下 -> 删除日志文件。我认为在第一个示例中发生在您身上的是您的计时器委托被不同线程多次调用。 感谢您的回复。我最初可以启动我的线程,但是,在完成更新我的记录后 - 它停止了计时器。而且我添加了更多记录来检查我的方法是否能够更新它。但是,无法成功更新行。 好的.. 我想我需要那里的日志文件来打印“无记录”因为 - 假设我们在数据库中有一些数据要更新,并且这次它完成了它的工作。稍后(5 或 10 秒后)它必须检查数据是否存在,如果存在则必须更新或记录 - 此时没有数据.. 除了你的答案 - 你能解释一下,是否可以为每个计时器间隔调用的方法创建一个线程? 试试这个:***.com/questions/5497466/…

以上是关于定时器方法虽然完成了它的任务,但它并没有停止执行的主要内容,如果未能解决你的问题,请参考以下文章

java定时执行任务为啥没有执行

crontab定时任务不执行的原因

java中定时执行任务,为啥方法没有执行完就不执行了?

收音机开始。但它并没有停止。当我在项目中切换页面时它不会停止

如何等到计时器在java中停止?

Centos7:利用crontab定时执行任务