一旦另一个线程完成,就会生成一个新线程

Spawn a new thread as soon as another has finished

本文关键字:线程 一个 新线程 另一个      更新时间:2023-10-16

我有一个昂贵的函数,需要执行 1000 次。执行可能需要 5 秒到 10 分钟。因此,它具有很高的变化。我喜欢有多个线程在上面工作。我目前的实现在 4 次 250 次调用中设计了这 1000 次调用,并生成了 4 个线程。但是,如果一个线程有"糟糕的一天",则与其他 3 个线程相比,它有更长的时间来完成。

因此,每当线程完成上一个调用时,我喜欢对该函数进行新的调用 - 直到所有 1000 次调用都完成。

我认为线程池可以工作 - 但如果可能的话,我喜欢有一个简单的方法(=尽可能少的额外代码(。基于任务的设计也朝着这个方向发展(我认为(。有没有简单的解决方案?

初始化具有

1000 个单位的信号量。 让 4 个线程中的每一个都围绕信号量 wait(( 和工作函数循环。

然后,所有线程都将处理该函数,直到它被执行 1000 次。即使其中三个线程卡住并花费很长时间,第四个线程也将处理其他 997 呼叫。

[编辑]呵呵..此外,标准 C++11 库不包括信号量。然而,信号量是一个基本的操作系统 sunchro 原语,因此应该很容易调用,例如。与POSIX。

您可以使用 Exectuors 的任一引用实现,然后通过以下方式调用该函数

#include <experimental/thread_pool>
using std::experimental::post;
using std::experimental::thread_pool;
thread_pool pool_{1};
void do_big_task()
{
    for (auto i : n)
    {
        post(pool_, [=]
        {
            // do your work here;
        });
    }
}

执行者将在C++17到来,所以我想我会早点进入。

或者,如果您想尝试另一种风格的执行器,那么有一个语法略有不同的最新实现。

鉴于您已经能够将调用分段为单独的实体和要处理的线程。一旦方法是使用std::package_task(及其关联的std::future(来处理函数调用,并将它们放在某种队列中。反过来,每个线程都可以拾取打包的任务并处理它们。

您将需要锁定队列以进行并发访问,这里可能会有一些瓶颈,但与线程可能"糟糕的一天"的担忧相比,这应该是最小的。这实际上是一个线程池,但它允许您对任务的执行进行一些控制。

另一种选择是使用 std::async 并将其启动策略指定为 std::launch::async ,缺点是您不控制线程创建本身,因此您取决于标准库控制线程的效率与拥有的内核数量。

无论哪种方法都有效,关键是在合理的样本量上衡量方法的性能。该度量应该是针对时间和资源的使用(线程和保持内核繁忙(。大多数操作系统将包括测量进程资源使用情况的方法。