我怎样才能完成ThreadPool.Join?

发布于 2024-09-13 05:27:35 字数 129 浏览 3 评论 0 原文

我正在编写一个使用 ThreadPool.QueueUserWorkItem() 的 Windows 服务。每个线程都是一个短暂的任务。

当服务停止时,我需要确保当前正在执行的所有线程都已完成。有什么方法可以等待队列自行清除吗?

I am writing a windows service that uses ThreadPool.QueueUserWorkItem(). Each thread is a short-lived task.

When the service is stopped, I need to make sure that all the threads that are currently executing complete. Is there some way of waiting until the queue clears itself?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

枫以 2024-09-20 05:27:51

执行此操作的标准模式是使用一个计数器来保存待处理工作项的数量,以及一个在计数器达到零时发出信号的 ManualResetEvent。这通常比为每个工作项使用 WaitHandle 更好,因为当存在大量同时工作项时,它不能很好地扩展。另外,某些静态 WaitHandle 方法无论如何只接受最多 64 个实例。

// Initialize to 1 because we are going to treat the current thread as
// a work item as well. This is to avoid a race that could occur when
// one work item gets queued and completed before the next work item
// is queued.
int count = 1;
var finished = new ManualResetEvent(false); 
try 
{ 
  while (...)
  {  
    Interlocked.Increment(ref counter);
    ThreadPool.QueueUserWorkItem( 
      delegate(object state) 
      { 
        try 
        { 
          // Your task goes here. 
        } 
        finally 
        { 
          // Decrement the counter to indicate the work item is done.
          if (Interlocked.Decrement(ref count) == 0) 
          { 
            finished.Set(); 
          } 
        } 
      }); 
  } 
}
finally
{
  // Decrement the counter to indicate the queueing thread is done.
  if (Interlocked.Decrement(ref count) == 0) 
  { 
    finished.Set(); 
  } 
}
finished.WaitOne(); 

The standard pattern for doing this is to use a counter which holds the number of pending work items and one ManualResetEvent that is signalled when the counter reaches zero. This is generally better than using a WaitHandle for each work item as that does not scale very well when there are a lot of simultaneous work items. Plus, some of the static WaitHandle method only accept a maximum of 64 instances anyway.

// Initialize to 1 because we are going to treat the current thread as
// a work item as well. This is to avoid a race that could occur when
// one work item gets queued and completed before the next work item
// is queued.
int count = 1;
var finished = new ManualResetEvent(false); 
try 
{ 
  while (...)
  {  
    Interlocked.Increment(ref counter);
    ThreadPool.QueueUserWorkItem( 
      delegate(object state) 
      { 
        try 
        { 
          // Your task goes here. 
        } 
        finally 
        { 
          // Decrement the counter to indicate the work item is done.
          if (Interlocked.Decrement(ref count) == 0) 
          { 
            finished.Set(); 
          } 
        } 
      }); 
  } 
}
finally
{
  // Decrement the counter to indicate the queueing thread is done.
  if (Interlocked.Decrement(ref count) == 0) 
  { 
    finished.Set(); 
  } 
}
finished.WaitOne(); 
定格我的天空 2024-09-20 05:27:48

您可以在每个线程中创建一个事件(例如ManualResetEvent),并将其保存在同步列表中(使用lock 构造)。任务完成后设置事件或将其从列表中删除。

当你想加入时,可以使用 WaitHandle.WaitAll (MSDN 文档)等待所有事件发出信号。

这是一个黑客,但我不知道如何将其简化为更简单的东西!


编辑:另外,您可以确保没有发布新事件,然后等待几秒钟。如果它们确实是短暂的,那么你就不会有问题。更简单,但更hacky。

最后,如果只是很短的时间,服务将不会退出,直到所有线程都死掉(除非它们是后台线程);因此,根据我的经验,如果时间很短,服务控制管理器不会介意一秒钟左右 - 您可以让它们过期。

You could create an event (e.g. ManualResetEvent) in each thread, and keep it in a synchronised list (using the lock construct). Set the event or remove it from the list when the task is finished.

When you want to join, you can use WaitHandle.WaitAll (MSDN documentation) to wait for all the events to be signalled.

It's a hack, but I can't see how to reduce it to anything simpler!


Edit: additionally, you could ensure that no new events get posted, then wait a couple of seconds. If they are indeed short-lived, you'll have no problem. Even simpler, but more hacky.

Finally, if it's just a short amount of time, the service won't exit until all threads have died (unless they are background threads); so if it's a short amount of time, the service control manager won't mind a second or so - you can just leave them to expire - in my experience.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文