System.Threading.Timer不连续

9

我在创建一个连续的计时器时遇到了问题。有多个错开的线程在定时器上创建,这些线程会运行一段时间,然后完全停止。我允许的最大线程数是5,计时器间隔设置为10000。因此理论上每2秒钟就会执行1个线程。

这种情况会持续一段时间,但之后就会停止。目前我正在测试控制台应用程序并将响应写入该应用程序。

我不确定这里到底发生了什么。

internal class EngineThreadGenerator
{
    private readonly AutoResetEvent _autoEvent;
    private readonly Action<string, string> _processQueueDelegate;
    private readonly Action<string, string> _purgeQueueDelegate;

    private void createAllowedEmailThreads()
    {
        for (int counter = 0; counter < AppSettings.ProcessQueueAllowedThreads; counter++)
        {
            EmailThread _emailThread = new EmailThread(_collection, _processQueueDelegate, _purgeQueueDelegate);
            TimerCallback _timerCallback = _emailThread.InitEmailThread;
            Timer _stateTimer = new Timer(_timerCallback, _autoEvent, 0, AppSettings.ProcessIntervalInMilliseconds);

            pauseLoop();
        }
    }

非常感谢您的帮助!干杯!


1
你是在说线程的生成停止了,还是线程本身停止了?"一段时间"指的是多长时间? - Lasse V. Karlsen
线程本身通常会在进程开始后的3分钟内停止。 - BoredOfBinary
2个回答

10

你的计时器在3分钟后停止工作是因为你有很多可用内存。

这意味着垃圾回收器需要大约3分钟才能到达您的对象并进行收集。

您应该在其生命周期中保留对计时器的引用。由于您没有这样做,一旦循环结束,计时器就有资格进行垃圾回收。

3分钟后或垃圾回收器完成回收时,计时器将被收集,您的代码将停止执行。

因此,请保留对计时器对象的引用,这样你就可以顺利运行了。

这里是一个简单的LINQPad脚本可供测试:

void Main()
{
    new Timer(Callback, null, 0, 1000);
    Thread.Sleep(5000);
    Debug.WriteLine("collecting");
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    Debug.WriteLine("collected");
    Thread.Sleep(5000);
}

static void Callback(object state)
{
    Debug.WriteLine("callback");
}

需要注意的是,一旦主线程运行GC,回调函数将停止。如果你把定时器复制到一个字段中:

Timer _Timer;

void Main()
{
    _Timer = new Timer(Callback, null, 0, 1000);
    ...
计时器在垃圾收集过程中仍然继续计时。

糟糕...我的构建也在控制台应用程序中,这也可以解释为什么不行吧? - BoredOfBinary
取决于你的控制台应用程序是否一直挂起,直到线程完成。如果是这样,或者至少应该是这样,那么使用控制台应用程序进行此操作就没有问题,只需不要让主线程(也称为 Program.Main)退出即可。当它退出时,中国的所有引用都无法保持计时器的活动状态。 - Lasse V. Karlsen
谢谢您的指导!我该如何保持主线程运行? - BoredOfBinary
好的,它需要保持运行多长时间呢?如果是无限期的,只需设置一个ManualResetEvent,并在其中等待,但永远不要发出信号。如果你正在等待某些东西,仍然使用ManualResetEvent,在其中等待,但当那个东西到来时发出信号。话虽如此,如果你正在构建一个被认为一直运行的程序,你真的应该考虑构建一个适当的Windows服务。 - Lasse V. Karlsen
我的意图是构建一个Windows服务,我只是为了测试目的创建了控制台。我将查看ManualResetEvent。谢谢,线程对我来说还比较新! - BoredOfBinary
@LasseV.Karlsen 谢谢你。你提供的信息不仅有帮助,而且还很有教育意义。无法感激你! - Nick Roberts

0
也许这段代码中没有展示,但是你有减少 counter 的值吗?

哇,被踩了?为什么?原始代码片段只会循环几次然后退出,这可能解释了为什么它可以运行“一段时间”然后停止。 - CodingWithSpike
如果我做了,那纯粹是意外。 - BoredOfBinary
不,我不会递减计数器,计数器只是用来遍历循环并创建计时器线程的。因此,如果我最多有5个,则只应创建五个计时器线程。 - BoredOfBinary
我也刚测试了计时器,没有循环,只创建了一个单线程,仍然停止了。 - BoredOfBinary

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