【问题标题】:When creating a new timer, what will happen to the old?创建新计时器时,旧计时器会发生什么?
【发布时间】:2019-10-04 13:48:12
【问题描述】:

我继承了一些旧代码,在我看来它的某些部分存在问题。

该程序使用 TCP/IP 与另一个程序通信,协议简单。发送命令电报并等待响应电报。

这是我认为有问题的部分。

public System.Timers.Timer retransmitTimer;

public TelegramBase SendAndWait(TelegramBase telegram)
{
    CurrentTelegram = telegram;

    retransmitTimer = new Timer(RetransmitInterval);
    retransmitTimer.Elapsed += retransmitTimer_Elapsed;

    //Send telegram
    Send(telegram);

    //Start timer
    retransmitTimer.Start();

    //Wait for response
    var response = WaitForResponse(telegram as StandardTelegram);

    //stop timer
    retransmitTimer.Stop();

    return response;
}

每次发送命令电报时都会调用方法 SendAndWait。

我的问题是计时器的创建

    retransmitTimer = new Timer(RetransmitInterval);
    retransmitTimer.Elapsed += retransmitTimer_Elapsed;

这将创建一个新的计时器,但当前的计时器从未被释放,所以它会继续运行?最好的情况是停止。

什么更好?

  1. 将计时器的创建移到只调用一次的方法中?
  2. 释放当前计时器,然后在 SendAndWait 中创建一个新计时器?

【问题讨论】:

  • 你不需要计时器。使用带有超时的CancellationToken
  • "所以它将继续运行" 这是一个问题还是一个声明?你试过了吗?你还会收到旧计时器触发的事件吗?
  • @HimBromBeere 这主要是一个问题,但是是的,有时会有旧计时器触发的事件。
  • 唯一真正关键的细节是计时器需要停止,所以他应该将 Stop() 调用放在 finally 块中以确保它是异常安全的。当您正确使用 using 语句时,您当然会自动获得它。您应该更担心的是即使收到响应,当计时器滴答时会发生什么。这很可能是您无法为 System.Timers.Timer 修复的线程竞争错误。只要确保它发生时不会爆炸。

标签: c# system.timers.timer


【解决方案1】:

我会将计时器包装在 using 语句中:

public TelegramBase SendAndWait(TelegramBase telegram)
{
    CurrentTelegram = telegram;

    using (Timer retransmitTimer = new Timer(RetransmitInterval))
    {
        retransmitTimer.Elapsed += retransmitTimer_Elapsed;

        //Send telegram
        Send(telegram);

        //Start timer
        retransmitTimer.Start();

        //Wait for response
        var response = WaitForResponse(telegram as StandardTelegram);

        //stop timer
        retransmitTimer.Stop();
    }

    return response;
}

【讨论】:

  • 托比,这很误导人使用语句创建了一个新的retransmitTimer,它隐藏了同名的属性!
  • @Toby Smith 这是我没有想到的选项!看起来很干净......但是应该删除公共 retransmitTimer ,不是吗?
  • @Andis59 - 是的,非常正确
【解决方案2】:

System.Timers.Timer 的描述来看,它似乎是一个很重的对象,所以用每条消息初始化它可能会有相当大的开销。如果您觉得自己在性能上苦苦挣扎,那么这将是一个值得关注的地方。与方法的其余部分相比,您可以做一些微基准来计算计时器构造函数的执行时间。

在您当前的实现中,retransmitTimer 应该是包含在 using 语句中的局部变量,正如您在另一个答案中看到的那样。

如果您决定为每个类使用一个计时器,那么您可以使用现有Timer 实例的Interval 属性来设置间隔,而不是使用RetransmittInterval 调用Timer 构造函数。使用此实现,您应该在包含SendAndWait 方法的类上实现IDisposable,并在您的类的Dispose 方法中配置计时器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-20
    • 2023-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多