【问题标题】:Wait for one of several threads to finish?等待几个线程之一完成?
【发布时间】:2010-11-24 07:40:24
【问题描述】:

我正在实现一个线程池。每个线程所需的工作是 1-10 秒的 CPU,因此我很高兴拥有一个带有工作人员的传统线程池,或者我很高兴为每个工作单元生成一个新线程。没关系。

我想有一些方法让主控制线程知道 N 个工作线程中的一个何时完成其工作并准备好进行更多工作(或开始另一个工作线程的时间)。我看过 pthread_join 和 pthread_cond_wait。似乎没有办法等待 N 中的一个。所以我考虑让主线程有一个变量,用于进入睡眠状态并让工作人员唤醒它。如果工人不死,这似乎可行。但是,如果他们死了,在工作人员唤醒控制器的时间和我不想处理的时间之间有一个窗口。

我查看了英特尔的 TBB,但它看起来比我需要的要复杂得多。

PTHREADS 中是否有与 Microsoft Windows 中的 WaitForMultipleObjects 等效的简单方法?

【问题讨论】:

  • 我将其标记为 C,如果不是这种情况,请随时更改。
  • 您是否尝试过对 pthread_join 进行循环 (N)。 opengroup.org/onlinepubs/007908799/xsh/pthread_join.html
  • 我同意 small_ticket。为什么循环 n 个 pthread_joins 不起作用?
  • @small/jay,等到所有线程完成有什么帮助? OP 想知道他们中的 any 何时完成。开始 10 个然后等待所有 10 个完成后再开始另一个不会很有效。
  • @paxdiablo vy32 写道:“我希望有一些方法让主控制线程知道 N 个工作线程中的一个何时完成其工作并准备好进行更多工作(或开始另一个工作的时间) “据我所知,他想等10点完成后再开始一个新的。我错了吗?

标签: c pthreads


【解决方案1】:

这是一个相当简单的条件变量用例。

对活动工作项的数量进行整数计数,受互斥体保护。此外,有两个条件变量,一个用于通知工作线程在队列上可用,另一个用于通知主线程线程已完成。比如:

main:
    set freethreads to numthreads
    init mutex M, condvars TOMAIN and TOWORKER
    start N worker threads
    while true:
        wait for work item
        claim M
        while freethreads == 0:
            cond-wait TOMAIN, M
        put work item in queue
        decrement freethreads
        cond-signal TOWORKER
        release M

worker:
    init
    while true:
        claim M
        while no work in queue:
            cond-wait TOWORKER, M
        get work to local storage
        release M
        do work
        claim M
        increment freethreads
        cond-signal TOMAIN
        release M

请注意,循环将永远运行。实际上,会有一些信号使它们退出并运行终止/清理代码。

【讨论】:

  • cond-signal 应该在释放互斥锁之前完成 - 否则,线程可能会在测试条件和等待之间收到信号。
  • 是的,@caf,当您写评论时,我意识到这一点。更新修复。
  • 嗨。这很有趣,但我认为您所做的是实现了一个基本的计数信号量,对吧?我喜欢使用 TOMAIN 和 TOWORKER。主线程休眠,直到其中一个工作者向它发送一条消息,指示空闲线程已增加并且多个工作者在 cond-wait 上休眠。这也假设有一个队列?我的问题---你真的试过这个吗?如果多个工人在等待会发生什么?我猜 cond-signal 保证只有其中一个会醒来?
  • @vy32,实际上,可能会唤醒不止一个(这是条件变量的本质),但只有一个会首先获取互斥锁。这就是为什么工人 cond-wait 在循环内,因为两个可能会醒来,第一个得到工作,第二个(当它最终得到互斥体时),看到一个空队列并继续循环。
  • @paxdiablo,所以 M 保护队列、TOWORKER 和 TOMAIN。这是非常好的。信号量解决方案的问题在于,主线程需要确定哪个工作人员真正醒来。这个解决方案可以避免这种情况。我很喜欢。谢谢。
【解决方案2】:

您是否考虑过使用计数信号量?

【讨论】:

  • 是的,信号量是这类事情的标准解决方案。
  • 标准的 1990 年代解决方案。 ;-)
【解决方案3】:

从架构的角度来看,这将是线程池的责任。工作人员和池之间应该存在同步。

pthread_mutex_lock() 或计数信号量(sem_wait() 和 sem_post() )对于这种同步很有用。一种方法可以说明为:

  1. 池初始化是计数信号量,通过调用:sem_init(p_to_sem_t, 0, int n);
  2. n 个工作人员通过调用获取信号量:sem_wait();
  3. 池通过调用:sem_wait(); 等待工作人员返回;
  4. 池检查信号量计数以查看是否所有工作人员都已停放。
  5. worker(s) 在退出时通过调用 sem_post(); 来释放他们的锁

【讨论】:

  • 如果您要等待多个工人中的一个重新加入,则应从程序中删除第 4 步。
  • 这看起来非常简单优雅。老实说,我不知道 文件 --- 我只是在查看 。有没有一种简单的方法可以知道 哪些 工人完成了,还是我需要维护一个单独的数组来跟踪它?
  • 在第二次反思中,这种方法的问题是主线程需要确定哪一个醒来才能让它工作......
  • 如果我没记错的话,POSIX 信号量的支持比线程少得多。而且条件变量的方法要好得多。
  • @vy32,有一个问题,您的员工积极主动吗?如果是这样,我建议您将工作队列集成到您的池中,以便每个工作人员都可以积极地从池中获取工作。如果您仍然需要一种方法来知道哪些工人被停在了后面,据我所知,应该使用数组和 ID。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多