如何在两个定时器之间创建延迟?

How to create delay between two timers?

目标

有两种方法:Add() 和 Remove()。

我的代码

        static bool keepGoing = true;

        static System.Timers.Timer AddMethodTimer= new System.Timers.Timer();
        static System.Timers.Timer RemoveMethodTimer = new System.Timers.Timer();

        private static void Execute()
        {
            if (!keepGoing)
            {
                AddMethodTimer.Stop();
                RemoveMethodTimer.Stop();
            }
            else
            {
                AddMethodTimer.Interval = 30; // X = 30
                RemoveMethodTimer.Interval = 5; // N = 5

                AddMethodTimer.Elapsed += new ElapsedEventHandler(Add);
                AddMethodTimer.Start();
                Thread.Sleep(RemoveMethodTimer.Interval)//In this case, N=5; 
                RemoveMethodTimer.Elapsed += new ElapsedEventHandler(Remove); 
            }
        }
        private static void Add(object source, ElapseEventArgs e)
        {
             //add operation
        }
        private static void Remove(object source, ElapseEventArgs e)
        {
            //remove operation
        }

用户只能更改 "keepGoing" 变量。如果它是假的,定时器应该停止。整个代码在更改时触发(我有一个 post IActionResult 来处理它。它工作正常。当 keepGoing 被更改时,它进入我提供的代码)。

注意 : 如果对象被插入到数据库中并且用户使 keepGoing 为 false,Remove() 将不会被执行

你可以试试异步方式。这不会在您的代码中使用 'use' 计时器。通过使用 CancellationTokenSource,您也可以取消 Task.Delays。

这是举例。你应该改进它,因为如果你在 30 秒延迟内取消它,它仍然会调用添加和删除。您可以为此使用 if (!tcs.IsCancellationRequested) Add();。随便玩玩吧。

static CancellationTokenSource tcs = new CancellationTokenSource();

private static async Task ExecuteAsync()
{
    while (!tcs.IsCancellationRequested)
    {
        await Task.Delay(30000, tcs.Token);

        Add();

        await Task.Delay(5000, tcs.Token);

        Remove();
    }
}

private static void Stop()
{
    tcs.Cancel();
}

private static void Add()
{
    //add operation
}

private static void Remove()
{
    //remove operation
}

坚持使用计时器,我建议这样:

private static System.Timers.Timer myTimer = null;
private static readonly syncObj = new object();

public static bool Execute( bool runTimer )
{
     if(runTimer)
     {
         lock(syncObj) // myTimer access shall be thread safe
         {
             if(myTimer != null) return false;
             // Timer is not active => activate
             myTimer = new System.Timers.Timer();
             myTimer.AutoReset = false; // 1-Time trigger!!
             myTimer.Elapsed += AddOnTimer;
             myTimer.Interval = TimeSpan.FromSeconds(30).TotalMilliseconds; // Interval is in ms!
             myTimer.Enabled = true;
         }
     }
     else
     {
        lock(syncObj)
        {
            if( myTimer == null ) return false;
            myTimer.Enabled = false;
            myTimer.Dispose();
            myTimer = null;
        }
     }
     return true;
}

private static void AddOnTimer(object sender, ElapsedEventArgs e)
{
    AddObjToDB();
    lock( syncObj )
    {
      if( myTimer == null ) return; // myTimer has been canceled, meanwhile
      myTimer.Elapsed -= AddOnTimer;    // Instead of Add, next time
      myTimer.Elapsed += RemoveOnTimer; // execute Remove
      myTimer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds;            
      myTimer.Enabled = true;
    }
}

private static void RemoveOnTimer(object sender, ElapsedEventArgs e)
{
    RemoveObjFromDB();
    lock( syncObj )
    {
      if( myTimer == null ) return; // myTimer has been canceled
      myTimer.Elapsed -= RemoveOnTimer;  // Instead of Remove, next time
      myTimer.Elapsed += AddOnTimer;     // execute Add
      myTimer.Interval = TimeSpan.FromSeconds(30).TotalMilliseconds;
      myTimer.Enabled = true;
    }
}

异步方法:

public static async Task Execute( CancellationToken cancel )
{
    while( !cancel.IsCancellationRequested )
    {
      await Task.Delay(TimeSpan.FromSeconds(30), cancel);
      await AddObjToDBAsync(cancel);
      await Task.Delay(TimeSpan.FromSeconds(5), cancel);
      await RemoveFromDBAsync(cancel);
    }
}

private static async Task AddObjToDBAsync( CancellationToken cancel )
{ 
   if( !cancel.IsCancellationRequested )
   {
       await YourDataLayer.AddAsync( someObj ); // <= I made this up, of course. "Async all the way" is recommended.
   }
}

private static async Task RemoveObjFromDBAsync( CancellationToken cancel )
{ 
   if( !cancel.IsCancellationRequested )
   {
       await YourDataLayer.RemoveAsync( someObj );
   }
}

*(我刚刚看到,Jeroen 已经发布了一个异步方法。无论如何,我会把它留在这里。)