代码之家  ›  专栏  ›  技术社区  ›  Kimi

系统线程计时器最大时间值问题

  •  2
  • Kimi  · 技术社区  · 14 年前

    According to the documentation 最大dueTime值为4294967294毫秒。但是如果您将计时器设置为这个值,它会立即触发回调。

    运行下面的程序,点击“c”-回调将立即启动,点击“o”,它将在49天后启动,点击“v”,它将在1s后启动。这是一个错误还是我做错了什么?

    using System;
    using System.Threading;
    
    namespace Test
    {
        class Program
        {
            private static bool isRunning;
            private static Timer t;
    
            static void Main(string[] args)
            {
                t = new Timer(OnTimerCallback, null, Timeout.Infinite, Timeout.Infinite);
                isRunning = true;
                while (isRunning)
                {
                    var command = Console.ReadKey();
    
                    switch (command.KeyChar)
                    {
                        case 'q':
                            isRunning = false;
                            break;
                        case 'c':
                            t.Change(TimeSpan.FromMilliseconds(4294967294), TimeSpan.FromMilliseconds(-1));
                            break;
                        case 'o':
                            t.Change(TimeSpan.FromMilliseconds(4294000000), TimeSpan.FromMilliseconds(-1));
                            break;
                        case 'v':
                            t.Change(TimeSpan.FromMilliseconds(1000), TimeSpan.FromMilliseconds(-1));
                            break;
                    }
                }
                Environment.Exit(0);
            }
    
            private static void OnTimerCallback(object x)
            {
                Console.WriteLine("Timer callback");
                t.Change(TimeSpan.FromMilliseconds(4294967294), TimeSpan.FromMilliseconds(-1));
            }
        }
    }
    

    更新

    如果您在回调中将timer设置为max dueTime值,它将不会立即启动,并且将按预期工作:)

    3 回复  |  直到 14 年前
        1
  •  3
  •   Hans Passant    14 年前

    这看起来像是CLR实现计时器的竞争。我需要向确切的原因挥手,我真的不明白怎么会出错。至少从SSCLI20源代码来看(clr\src\vm\win32线程池.cpp),很有可能这与当前的装运代码不再准确。

    通过在Change()调用处设置断点,我可以很容易地重新编程这个问题,但当我让代码不间断地运行时就不行了。它的行为类似于从GetTickCount()返回的上一个观察值(而不是当前值)计算到期时间。将0xfffffe添加到该过时值,然后计算已经过期的时间。滴答数只有32位的分辨率。我认为真正的竞争在于计算SleepEx()等待下一次到期事件的时间,但这只是猜测。

        2
  •  1
  •   Lasse Espeholt    14 年前

    这其实是个有趣的问题。我试图在反射器中查看该方法,但最终得到了一个本机内部调用。

    但你为什么要这么做?根据文件你可以改变 dueTime -1 Timeout.Infinite 像在构造函数中一样禁用它。

    您还可以使用:

    t.Change(4294967294u, -1u);
    

    而不是

    t.Change(TimeSpan.FromMilliseconds(4294967294), TimeSpan.FromMilliseconds(-1));
    
        3
  •  1
  •   Richard    14 年前

    4294967295正在 UIn32.MaxValue ,因此4294967294按位转换为 int 应该是-2。

    但是我在文档中看不到任何明确说明这个值是可以的。列出0和-1。

    [参见注释:这只是转换为 UInt32 long 过载 Timer.Change ,这将提供更大的范围?

    附加:查看 SetWaitableTimer (我明白这一点 System.Threading.Timer Waitable Timers )我明白了,对于到期时间参数:

    负值表示相对时间。