我需要创建一堆定时器作为局部变量来执行以下操作:
void Foo()
{
Timer t = new Timer(myTimerCallback,null,1000,Timeout.Infinite);
}
不幸的是,其中一些是由GC收集的,然后在1秒后调用myTimerCallback。由于我有很多计时器,因此无法将它们存储在私有静态成员中。并且很难找到放置GC.Keeplive(t)的地方。
我怎样才能让每个计时器在临终前做好自己的事情?
答案 0 :(得分:2)
您最好的选择是将它们存储在成员变量中,然后在不再需要它们时将其丢弃。
答案 1 :(得分:1)
将它们存储在成员中,例如List<Timer>
。
答案 2 :(得分:1)
为什么无法存储它们?也许你可以在他们的工作完成后从那个系列中删除它们?
答案 3 :(得分:1)
重要的是要看到GC.KeepAlive()无法解决您的问题。这只会将对象的生命周期延长到语句。只要计时器需要保持活动,你就必须循环或阻塞。还要注意,Debug构建中局部变量中引用的生命周期是不同的。 JIT让它们保持生命直到方法结束,以允许手表工作。制作棘手的“在调试中工作,在发布模式下不起作用”的问题。
您必须保留对计时器对象的生命引用。这通常是通过类中的字段完成的。生命周期要求现在传递给类对象,只要需要计时器,它就需要保持活动状态。通常不是问题。如果是,则必须使参考静态。
答案 4 :(得分:1)
您可以将它们存储在集合中以保留引用,并在事件方法中从集合中删除引用。我认为您需要使用state参数来标识集合中的计时器(将对定时器的引用或集合中的键作为“new timer”语句中的状态参数传递)。
请注意,回调函数在其他线程上执行,因此您可能/可能同时运行多个回调函数。使用锁定确保安全地完成添加/删除引用。
答案 5 :(得分:0)
值得指出的是,保留引用问题特定于System.Threading.Timer
而非System.Timers.Timer
。
这不是解决您的问题的方法,但我认为它仍然与主题相关。
System.Threading.Timer
的{{1}}构造函数(不使用Timer(TimerCallback callback)
的构造函数)对dueTime
使用this
,这意味着计时器将保留对自身的引用,这意味着它将在垃圾回收中幸免。
state
计时器'C'是使用public Timer(TimerCallback callback)
{
(...)
TimerSetup(callback, this, (UInt32)dueTime, (UInt32)period, ref stackMark);
}
创建的,并且一直沿用Timer(TimerCallback callback)
。
GC.Collect()
A
B
C
A
B
C
GC Collected
B
C
C
B
B
C