C#计时器回调

4

如果我像这样设置一个计时器:

var MyTimer = new Timer(RunTask, AutoEvent, 1000, 2000);

是否保证RunTask始终在同一线程上运行?

我的所有测试似乎都表明是这样的,但这是一个保证还是运气呢?

这非常重要,因为我需要存储持续调用之间保留的变量,而我目前在这些变量上使用 [ThreadStatic] 属性。

我知道如果回调比计时器延迟时间长,则计时器会在另一个线程上进行另一个回调;因此,我将问题缩小到没有并行运行的情况下(在回调期间阻止计时器)。


6
从文档中得知:回调方法需要是可重入的,因为它在线程池线程上被调用。如果计时器间隔小于执行方法所需的时间,或者线程池线程全部被占用并且方法被多次排队,则该方法可以同时在两个线程池线程上执行。https://msdn.microsoft.com/zh-cn/library/ms149618(v=vs.110).aspx - Oliver
我添加了一些澄清内容;如果没有线程保证,如何在一次调用和另一次调用之间保持上下文? - Thomas
2个回答

6
< p > System.Threading.TimerCallback委托允许您将上下文对象传递给回调方法。您可以使用此上下文对象将状态传递到回调处理程序中。这样,无论在哪个线程上回调,您都不需要使用ThreadStatic。

您传递给Timer构造函数的state参数将传递给回调方法。


6
回答您的问题,TimerCallback没有"保留"线程。该事件由线程池调度,并不能保证下一次的Tick会发生在同一个线程上,即使这种情况是可能的。
一个简单的测试可以说明这一点:
myTimer = new System.Threading.Timer(timer_Elapsed, null, 0, Timeout.Infinite);

static void timer_Elapsed(object state)
{
    Thread.Sleep(100);
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    myTimer.Change(100, Timeout.Infinite);
}

以下是结果:

在此输入图片描述


1
这就是为什么我很好奇,我在我的系统上也做了同样的事情(在Mac上的虚拟机中运行Windows Server 2016),只要回调及时完成,它总是会选择相同的线程,但我无法理解如何保证它。不管怎样,感谢您提供示例。 - Thomas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接