2

我不确定如何最好地取消正在运行系统计时器的任务。在下面的代码中,每 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();
        });
    }
4

4 回答 4

3

我建议您使用 Microsoft 的 Reactive Framework (aka Rx) - 只是 NuGet System.Reactive

然后你这样做:

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

当您想取消订阅时,只需调用subscription.Dispose().

Rx 非常适合抽象出计时器、事件、任务、异步操作等。

于 2019-02-10T01:23:02.203 回答
1

为什么不在调用上下文中(或在您的类/应用程序中全局访问)有一个可访问的计时器 - 无论如何您都必须这样做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();
于 2019-02-10T01:16:27.037 回答
1

你可以把你的方法改成这样

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

您可以在程序已处理或仅在主函数结束时取消此令牌

于 2019-02-10T00:56:57.027 回答
0

我在下面发布了似乎对我有用的令人满意的解决方案。希望我以正确的方式响应线程......(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();
    }
}
于 2019-02-10T13:49:01.110 回答