Как создать задержку между двумя таймерами? - PullRequest
0 голосов
/ 03 апреля 2020

ЦЕЛЬ

Имеется два метода: Добавить () и Удалить ().

  • Метод Add () происходит каждые X секунд, пока не будет остановлен пользователем; Добавляет объект в БД; Ждет N секунд; вызывает Remove ();

  • Метод Remove () вызывается методом Add () и удаляет объект, добавленный методом Add ().

Мой код

        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. Если оно ложно, таймер должен остановиться. Весь этот код запускается при изменении (у меня есть пост IActionResult, который обрабатывает его. Он отлично работает. Когда keepGoing изменен, он вводит код, который я предоставил).

ПРИМЕЧАНИЕ : Если объект вставлен в БД и пользователь делает keepGoing false, Remove () не будет выполняться

Ответы [ 2 ]

4 голосов
/ 03 апреля 2020

Вы можете попробовать асин c. Это не использует таймеры в вашем коде. Используя CancellationTokenSource, вы также можете отменить Task.Delays.

Это, например,. Вы должны улучшить его, потому что если вы отмените его в течение 30 секунд, он все равно будет вызывать Add и Remove. Вы можете использовать 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
}
1 голос
/ 03 апреля 2020

Придерживаясь таймера, я бы предложил что-то вроде этого:

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;
    }
}

Asyn c подход:

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 уже опубликовал asyn c подход. Я все равно оставлю это здесь.)

...