2011-04-05 48 views
1

我正在处理我的第一个涉及一些基本线程/并行性的Windows服务项目。到目前为止它一直非常强烈,但我慢慢开始理解线程(我想我们会看到这个...)。等待线程在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上加入thread.join,因为我只有两个工人,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)); 
     }); 
    } 

回答

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来确定是否还有线程挂起。

+0

+1你的答案是最多方面的,并且是首先提到CountdownEvent,这似乎是要走的路。 – HAL9000 2011-04-05 22:34:31

1

您目前的方法可能无法正常工作 - 您无法控制多少个线程实际上创建了多少线程,并非所有线程连接都可以并行运行 - 这完全取决于这些任务如何在线程池上进行调度。最重要的是,它的效率非常低,因为你产生的所有线程基本上都在等待。

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

+0

+1优点 - 我一直忘记TPL使用ThreadPool,你永远不知道它有多深 - gah信息超载! – HAL9000 2011-04-05 22:30:45

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)); 
+0

+1感谢您详细介绍CountdownEvent方法。 – HAL9000 2011-04-05 22:32:37