【问题标题】:C# System.Threading.Timer and its state objectC# System.Threading.Timer 及其状态对象
【发布时间】:2010-04-22 10:36:12
【问题描述】:

我正在编写一个 C# 程序,它使用 System.Threading.Timer 在 UDP 套接字 ReceiveAsync 调用上超时。

我的程序轮询远程设备,发送一个 UDP 数据包并期待一个回报。

我在单次模式下使用计时器调用 Timer.Change 每次我想要一个新的超时时间。

对于每次发生的超时,我都希望超时处理程序有不同的信息。

如果我更改了在创建时传递给 Timer 的对象,它在处理程序执行时似乎并没有改变。

这样做是为了销毁计时器并创建一个新计时器的唯一方法吗?

谢谢,

【问题讨论】:

  • 很遗憾没有人回答你

标签: c# .net


【解决方案1】:

你传递的是结构体而不是类对象吗?结构是值类型,您将获得它的第一个版本的副本。您所做的更改将丢失,因为回调中的 ref 没有传递状态。使用类而不是结构是简单的解决方案。

将状态对象存储在您自己的类中是另一种方法。

【讨论】:

  • 我刚刚意识到这不是真正的问题。真正的问题是我需要能够在每次执行单次拍摄时将状态传递给计时器,以便状态与完成数据包一起运行。无论计时器是复制我传递给它的状态还是使用原始状态,它都不会让您在每次运行时都传递一个新的状态而不破坏和重新制作计时器(我不愿意这样做)。跨度>
  • 好吧,如果您使用引用类型作为对象,那么您可以更改该对象的状态。我可能遗漏了一些东西,因为我没有看到或从未使用过该对象。
  • 是的,是否可以传入对象并不重要,因为您只能为整个计时器选择一个。您真正想要的是每次运行计时器一次。现在我要做的是我只使用计时器让我有机会检查另一个时间(使用 Environment.TickCount)。如果那个时间超过了我的超时时间,那么我才会采取超时操作。它不那么漂亮,但它对我有用。
【解决方案2】:

您传递的对象可以是一个数组,其中包含您在每次超时时替换的单个元素。

【讨论】:

    【解决方案3】:

    考虑一下这个便宜的包装器:

    sealed class TimerWrapper : IDisposable
    {
        readonly Timer timer;
    
        object State { get; set; }
    
        public TimerWrapper(TimerCallback callback) 
        {
            timer = new Timer(delegate { callback(State); });
        }
    
        public void Change(object state, TimeSpan dueTime, TimeSpan period)
        {
            timer.Change(dueTime, period);
            State = state;
        }
    
        public void Dispose()
        {
            timer.Dispose();
        }
    }
    

    请注意,使用上面的代码可能会在一些罕见的竞争条件下导致意外行为。

    【讨论】:

    • 我在 IO 完成回调和计时器之间存在竞争,这意味着我的 IO 没有按时完成。定时器事件可能会在执行队列之前发布到执行队列,然后执行我的 IO 完成。在这种情况下,因为我在旧 IO 完成后启动新 IO,所以新 IO 会因错误超时而终止。如果超时事件可以携带 IO 操作的 ID,那么即使发生这种罕见的情况,它也会知道不终止当前的 IO 操作。那是你指的罕见的比赛条件吗?
    【解决方案4】:

    使用 WaitHandle 和 lock 进行同步

    【讨论】:

      猜你喜欢
      • 2017-09-29
      • 2018-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-21
      • 1970-01-01
      • 2016-05-21
      • 2012-07-21
      相关资源
      最近更新 更多