等待线程在Windows服务中停止

时间:2011-04-05 21:46:27

标签: c# multithreading windows-services worker

我正在开发我的第一个涉及一些基本线程/并行性的Windows服务项目。到目前为止它一直非常激烈,但我慢慢开始理解线程(我想我们会看到它......)。

我有一个Windows服务,它将包含2个松散耦合的工作线程。线程A将从FTP服务器下载文件,解压缩/准备它们并保存到线程B将有一个FileSystemWatcher观看的另一个目录。线程B将解析文件,对数据执行大量操作,进行一些http调用,最后归档并从工作目录中删除文件。

我刚开始工作,我现在面临的问题是如何等待线程A和线程B都返回。我看了这个问题:Thread.Join on multiple threads with timeout并有了一个想法。

问题是如果我们等待x个线程以每个ax的第二次超时返回,有足够的线程,即使在正常操作下服务也可能看起来没响应(我在SCM抱怨之前读取超时30秒,对?)。另外,如果我们通过跟踪线程上的连接剩余时间来解决这个问题,那么我们在工作集合开始时等待线程的时间越长,剩余线程返回的时间就越少 - 所以最终如果所有线程都在预期的时间内返回,那么即使所有线程都在预期的时间内返回,服务也会显示无响应。

在这种情况下,我可能只是在14秒的超时时间内连接A和B.因为我只有两个工作人员,14秒似乎有足够的时间返回两者。

如果我有一个可变数量的工作线程(让我们说> 8),是否值得做这样的事情?这可行吗?

注意:请勿使用以下内容 - 这在多个级别上都是个坏主意。见答案

    protected override void OnStop()
    {
        // the service is stopping - set the event
        Worker.ThreadStopEvent.Set();

        // stop the threads
        Parallel.ForEach(_workerThreads, t =>
        {
            t.Join(new TimeSpan(0, 0, 28));
        });
    }

3 个答案:

答案 0 :(得分:1)

我建议您不要为每个线程使用超时,而是设置事件,然后定期执行Join更短的超时。极端版本将是:

Worker.ThreadStopEvent.Set();
Thread.Sleep(30000); // wait 30 seconds
// Now try to Join each thread, with a very short (20 ms, maybe) timeout.

这种方法的最大问题是你总是会等待30秒,即使所有线程都在五秒内停止。

你可以用一个睡眠一秒钟然后进行检查的循环做得更好。然后,您可以跟踪哪些线程已停止,并在所有线程停止时退出循环。

尽管使用CountdownEvent,你可能还是最好的。每个线程在停止时发出信号,主线程等待直到所有线程都停止。 Wait方法允许您指定超时值。在等待之后,您可以通过在非常短暂的超时时间内调用Join来确定是否仍有任何线程挂起。

答案 1 :(得分:1)

您当前的方法可能效果不佳 - 您无法控制Parallel.ForEach实际创建的线程数,并非所有线程连接都可以并行运行 - 这一切都取决于这些任务在线程池。最重要的是它效率很低,因为你产生的所有线程基本上都在等待。

如果这些工作线程没有必须在服务关闭时完成的关键任务,那么我会将它们作为所有后台线程 - 在这种情况下,您根本不需要处理这个问题。

答案 2 :(得分:1)

从技术上讲,您不必等到线程完成(加入),直到它们报告完成为止。因此,您可以使用在所有线程之间共享的CountdownEvent实例并等待它。所有线程都必须在finally块中递减事件:

void WorkerThread (object args)
{
  try
  {
    // actual work here
    ... 
  }
  finally
  {
    sharedCountdown.Signal();
  }
}

以及何时执行关闭并等待线程结束:

// Notify all workers of shutdown
...

// Now wait for all workers to complete, up to 30 seconds
sharedCountdown.Wait(TimeSpan.FromSeconds(30));