Как правильно остановить таймер - PullRequest
0 голосов
/ 08 января 2019
using System.Timers;

void CreateTimer()
{
    myTimerObject = new Timer(5000);
    myTimerObject.AutoReset = false;                 
    myTimerObject.Elapsed += MyEventOnElapsed;
    myTimerObject.Start();
}

void MyEventOnElapsed(object sender, ElapsedEventArgs e)
{
    lock(aLockObject) 
    {
         myTimerObject.Stop();
         // Perform actions that can exceed the interval time set in the timer
         myTimerObject.Start();
    }
}

void MethodTrigerredToStopTimer()
{
    lock(aLockObject)
    {
        myTimerObject.Stop();
    }
}        

В приведенном выше коде моему истекшему событию (MyEventOnElapsed) потребуется некоторое время для завершения, и поэтому мне пришлось использовать таймер запуска и остановки как часть этого метода. Когда сработает MethodTriggeredToStopTimer, давайте предположим, что код на MyEventOnElapsed и достиг блокировки, однако поток на MethodTriggerredToStopTimer выигрывает гонку и получает блокировку, мой таймер будет остановлен MethodTriggeredToStopTimer(). Однако после снятия блокировки указатель выполнения, ожидающий блокировки (aLockObject) в MyEventOnElapsed, будет продолжать запускать / останавливать таймер в течение неопределенного времени. Как обращаться с таймерами в этой ситуации?

Ответы [ 2 ]

0 голосов
/ 08 января 2019

Один из вариантов - спросить у таймера, включен ли Timer, прежде чем останавливать (отключать) его. Таким образом, если будет вызван MethodTrigerredToStopTimer, он поймет, что он был остановлен специально, и не запустит его снова.

void MyEventOnElapsed(object sender, ElapsedEventArgs e)
{
    lock(aLockObject) 
    {
        if (myTimerObject.Enabled)
        {    try
             { 
                 myTimerObject.Stop();
                 // Perform actions that can exceed the interval time set in the timer
             }
             finally 
             {
                 myTimerObject.Start();
             }
        }
    }
}

try finally помогает обеспечить перезапуск таймера к моменту выхода из lock (даже если выдается исключение).

0 голосов
/ 08 января 2019

Если вы хотите получить определенный способ остановки с помощью вызова метода или триггера при управлении таким циклом, вам нужно будет сохранить значение boolean isStopped или подобное:

boolean isStopped = false;

void CreateTimer()
{
    myTimerObject = new Timer(5000);
    myTimerObject.AutoReset = false;                 
    myTimerObject.Elapsed += MyEventOnElapsed;
    myTimerObject.Start();
}

void MyEventOnElapsed(object sender, ElapsedEventArgs e)
{
    lock(aLockObject) 
    {
         if (isStopped)
             return;

         myTimerObject.Stop();
         // Perform actions that can exceed the interval time set in the timer
         myTimerObject.Start();
    }
}

void MethodTrigerredToStopTimer()
{
    lock(aLockObject)
    {
        isStopped = true;
        myTimerObject.Stop();
    }
}

Все это было бы намного лучше в классном маленьком классе-обертке, с переменной состояния, названной примерно как Enabled, чтобы избежать путаницы с именами, сходными с Timer 'start и stop методами. Кроме того, я хотел бы взглянуть на построение этого цикла, используя Task, Task.Delay и CancellationToken, а также, если вам в конечном итоге понадобится межплатформенная поддержка или вы захотите обрабатывать такие вещи, как отмена во время вашей длительной операции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...