c# Отмена задачи при использовании System.Timers

Я не уверен, как лучше всего отменить задачу, в которой запущен системный таймер. В приведенном ниже коде каждые 60 минут таймер срабатывает, а затем запускает другой метод (CheckFileOverflow), который используется для проверки размера файла системного журнала txt. файл

Отмена таймера в идеале должна выполняться нажатием кнопки или другим методом, вызывающим отмену. Таймеру будет разрешено работать до тех пор, пока работает программное обеспечение, но когда пользователь в конечном итоге выключит программное обеспечение, я хотел бы иметь возможность отменить задачу ответственным образом, т.е. не подвергать риску текущий пул потоков ресурсы затяжные используются в фоновом режиме.

Я провел много часов, читая о токенах отмены, но до сих пор не понял :(

public void SystemEventLoggerTimer()
    {
        SysEvntLogFileChckTimerRun = true;

        Task.Run(() =>
        {
            System.Timers.Timer timer = new System.Timers.Timer
            { Interval = 1000 * 60 * 60 };
            timer.Elapsed += new ElapsedEventHandler(CheckFileOverflow);
            timer.Start();
        });
    }

person OJB1    schedule 10.02.2019    source источник
comment
когда вызывается SystemEventLoggerTimer()?   -  person d.moncada    schedule 10.02.2019


Ответы (4)


Я бы посоветовал вам использовать Microsoft Reactive Framework (он же Rx) — просто NuGet System.Reactive.

Затем вы делаете это:

IDisposable subscription =
    Observable
        .Interval(TimeSpan.FromHours(1.0))
        .Subscribe(_ => CheckFileOverflow());

Если вы хотите отменить подписку, просто позвоните subscription.Dispose().

Rx идеально подходит для абстрагирования таймеров, событий, задач, асинхронных операций и т. д.

person Enigmativity    schedule 10.02.2019

Вы можете изменить свой метод на что-то вроде этого

  public void SystemEventLoggerTimer(CancellationToken cancelToken)
        {
            SysEvntLogFileChckTimerRun = true;

            Task.Run(async () =>
            {
                // Keep this task alive until it is cancelled
                while (!cancelToken.IsCancellationRequested)
                {
                    await Task.Delay(TimeSpan.FromMinutes(60));
                    CheckFileOverflow();
                }
            });
        }

Затем вы вызываете SystemEventLoggerTimer следующим образом

var cancelSource = new CancellationTokenSource();
SystemEventLoggerTimer(cancelSource.Token);

вы можете отменить этот токен, когда программа была удалена или просто в конце вашей основной функции

person Amir Hossein Esmaill Zade    schedule 10.02.2019

Почему бы просто не иметь таймер, доступный в контексте вызова (или глобально в вашем классе/приложении) - вам все равно придется делать это с CancellationTokenSource! Это не похоже на правильный вариант использования Task.

Попробуй это:

    public void SystemEventLoggerTimer(System.Timers.Timer timer)
    {
        SysEvntLogFileChckTimerRun = true;

        timer.Elapsed += new ElapsedEventHandler(CheckFileOverflow);
        timer.Start();
    }

Код вызова:

    var timer = new System.Timers.Timer() { Interval = 1000 * 60 * 60 };
    SystemEventLoggerTimer(timer);

Код отмены (в обработчике событий кнопки отмены и т. д.):

    timer.Stop();
person CoolBots    schedule 10.02.2019
comment
Здравствуйте, этот подход, к сожалению, не сработал для меня, кажется, нет способа остановить таймер после его запуска? - person OJB1; 10.02.2019
comment
Последняя строка в моем ответе: timer.Stop(); - запустите этот код при нажатии кнопки, которую вы хотите использовать для остановки таймера (согласно вашему исходному сообщению) - person CoolBots; 10.02.2019
comment
Просто убедитесь, что объект таймера объявлен в Form1 в вашем коде, а не внутри какого-либо метода - возможно, поэтому вы не можете получить к нему доступ. - person CoolBots; 10.02.2019

Я разместил ниже то, что кажется удовлетворительным решением, которое сработало для меня. Надеюсь, я правильно отвечаю на ветку... (новичок в stackOverflow) Я настроил быструю форму Windows для тестирования, я создал кнопки 2qty и текстовое поле 1qty. Кнопки используются для запуска и остановки таймера (с использованием токена отмены). Текстовое поле используется для мониторинга таймера, который будет обновляться сообщением «Таймер работает» каждые 2 секунды. Надеюсь, это поможет любому, кто смотрит на подобный сценарий...

введите здесь описание изображения

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private CancellationTokenSource cancelSource;

    // Button is used to START the timer.
    private void TimerStartButton_Click(object sender, EventArgs e)
    {
        cancelSource = new CancellationTokenSource();
        // Run the below method that will initiate timer to start running from 
        // the button click.
        SystemEventLoggerTimer(cancelSource.Token);
    }

    private void SystemEventLoggerTimer(CancellationToken cancelToken)
    {
        Task.Run(async () =>
        {
            // Keep this task alive until it is cancelled
            while (!cancelToken.IsCancellationRequested)
            {
                // Encapsulating the function Task.Delay with 'cancelToken'
                // allows us to stop the Task.Delay during mid cycle.
                // For testing purposes, have reduced the time interval to 2 secs.
                await Task.Delay(TimeSpan.FromSeconds(2), cancelToken);
                // Run the below method every 2 seconds.
                CheckFileOverflow();
            }
        });
    }

    // When the below method runs every 2 secs, the UpdateUI will allow
    // us to modify the textbox form controls from another thread.
    private void CheckFileOverflow()
    {
        UpdateTextbox("Timer Running");
    }

    // UpdateUI will allow us to modify the textbox form controls from another thread.
    private void UpdateTextbox(string s)
    {
        Func<int> del = delegate ()
        {
            textBox1.AppendText(s + Environment.NewLine);
            return 0;
        };
        Invoke(del);
    }

    // Button that is used to STOP the timer running.
    private void TimerStopButton_Click(object sender, EventArgs e)
    {
        // Initiate the cancelleation request to method "SystemEventLoggerTimer"
        cancelSource.Cancel();
    }
}
person OJB1    schedule 10.02.2019