简体   繁体   English

C++线程池中的线程执行顺序

[英]C++ Thread execution order in a thread pool

Does anyone know of a C++ thread pool implementation that allows both parallel threading (like a typical thread pool) but also allows for back to back serial execution order.有谁知道 C++ 线程池实现,它既允许并行线程(如典型的线程池),又允许背靠背串行执行顺序。 I have spent several days trying to make this work by modifying the following thread pool but I cannot seem to make it work.我花了几天时间试图通过修改以下 线程池来完成这项工作,但我似乎无法让它工作。 I have looked into the techniques used by intel TBB, and also I looked into possibly using the concepts from microsoft's PPL (its asynchronous agents library looks promising) - both of which have task oriented techniques to achieve the above - Unfortunately however, these solutions will not work my target PowerPC linux embedded target.我研究了英特尔 TBB 使用的技术,也研究了可能使用微软 PPL 的概念(它的异步代理库看起来很有希望)——两者都有面向任务的技术来实现上述目标——不幸的是,这些解决方案将不工作我的目标 PowerPC linux 嵌入式目标。

EDIT I put together a live coliru demo with source that produces the thread graph - and also shows a good example of a scheduler_loop where theoretically one could wait for threads to complete.编辑我将一个实时的coliru演示与生成线程图的源代码放在一起 - 并且还展示了一个很好的scheduler_loop示例,理论上可以等待线程完成。 The code also shows a UtlThreadPool with 2 threads where I feed it with the concurent tasks - however that 'feeding' is not fully correct and will need a little work to traverse through the nodes.该代码还显示了一个带有 2 个线程的 UtlThreadPool,我在其中向它提供并发任务 - 但是“馈送”并不完全正确,需要做一些工作才能遍历节点。

The data structure that I use to make an execution graph is shown below.我用来制作执行图的数据结构如下所示。 It uses a PriorityNode data structure.它使用PriorityNode数据结构。 This structure is essentially a linked list of PriorityNodes, each one contains a vector of PriorityLevel tasks that can run concurrently and a pointer to the next PriorityNode which indicates the threads to be run serially afterwards.这个结构本质上是一个 PriorityNode 的链表,每一个都包含一个可以并发运行的PriorityLevel任务向量和一个指向下一个 PriorityNode 的指针,该指针指示之后要串行运行的线程。 Once these have ALL completed, if the mNextNode member is not a nullptr, then this should be scheduled to run in the thread pool (and so forth until the mNextNode is nullptr. Sequencing through this linked list of PriorityNodes is how I would like the thread pool to sequence through its threads. The PriorityNode has insertion operator that typically produces output as follows. (this would mean that 1A1 can be run concurrently with 1A2 and when both of these threads have completed the next PriorityNode would allow 1B1, 1B2, 1B3 and 1B4 to run concurrently - on however many threads the pool has available.一旦这些都完成了,如果 mNextNode 成员不是 nullptr,那么这应该被安排在线程池中运行(依此类推,直到 mNextNode 为 nullptr。通过这个 PriorityNodes 链表进行排序是我想要线程的方式池以通过其线程进行排序。PriorityNode 具有插入运算符,通常会产生如下输出。(这意味着 1A1 可以与 1A2 并发运行,当这两个线程都完成后,下一个 PriorityNode 将允许 1B1、1B2、1B3 和1B4 并发运行 - 无论池中有多少线程可用。

1A1
1A2
+-1B1
+-1B2
+-1B3
+-1B4

The nearest thing I have seem to a solution to this problem - again note it is intel specific and I am on power PC is the intel TBB - here is the example they use for serial execution order.我似乎解决这个问题的最接近的东西 - 再次注意它是特定于英特尔的,我在电源 PC 上是英特尔 TBB - 是他们用于串行执行顺序的示例。

/**
 * Branch representing fundamental building block of
 * a priority tree containing szPriority entries.<p>
 *
 * Each priority tree struct contains a vector of concurrent
 * priorities that can be scheduled to run in the thread pool -
 * note that the thread pool must have no entries associated
 * with the current channel running before enqueueing these
 * tasks. The application must wait for the thread pool to
 * complete these tasks before queuing up the dependent tasks
 * described in the mNextNode smart pointer. If mNextNode is
 * unassigned (nullptr), then we have reached the end of the
 * tree.
 */
struct PriorityNode {
    explicit PriorityNode(
        const std::vector<PriorityLevel>& rConcurrent,
        const std::shared_ptr<PriorityNode>& rNext = std::shared_ptr<PriorityNode>(),
        const size_t& rDepth = 0)
        : mConcurrent(rConcurrent)
        , mNextNode(rNext)
        , mDepth(rDepth)
    {}

    /**
    * Stream insert operator<p>
    *
    * @param os     [in,out] output stream
    * @param rhs    [in] PriorityLevel to send to the output
    *               stream.
    *
    * @return a reference to the updated stream
    */
    inline friend std::ostream& operator << (
        std::ostream& os, const PriorityNode& rhs) {
        // indent 2 spaces per depth level
        std::string indent = rhs.mDepth > 0 ?
            (std::string("+") +
            std::string((rhs.mDepth * 2) - 1, '-')) :
            std::string();
        // print out the concurrent threads that 
        // can be scheduled with the thread pool
        for (const auto& next : rhs.mConcurrent) {
            os << indent << next << std::endl;
        }
        // print the dependent priorities that can only
        // be scheduled when the concurrent ones are finished
        if (rhs.mNextNode) {
            os << *rhs.mNextNode << std::endl;
        }
        return os;
    }
    // these are all equivalent thread priorities
    // that can be run simultaneously
    std::vector<PriorityLevel> mConcurrent;

    // these are concurrent threads that must be AFTER all 
    // mConcurrent tasks have completed (exiting the thread pool)
    std::shared_ptr<PriorityNode> mNextNode;

    // recursion depth
    size_t mDepth;
};

Why not just use TBB on PowerPC?为什么不在 PowerPC 上使用 TBB? It is a highly portable library designed to be as cross-platform as practical;它是一个高度可移植的库,旨在尽可能地跨平台; and I've heard it is [being] ported on BlueGen by TBB open-source community.我听说它正在被 TBB 开源社区移植到 BlueGen 上。 You can ask them on the Intel TBB forum, for example, by reviving this forum thread .您可以在英特尔 TBB 论坛上提问,例如,恢复此论坛主题

Intel does not distribute PowerPC binaries for TBB but you can try build it from sources simply by Intel 不会为 TBB 分发 PowerPC 二进制文件,但您可以尝试从源代码构建它

make tbb做tbb

See also these community patches .另请参阅这些社区补丁

If anyone is still looking for this, check out the repo here - https://github.com/hirak99/ordered_thread_pool如果有人仍在寻找这个,请查看这里的 repo - https://github.com/hirak99/ordered_thread_pool

Basically with this you can replace code like this -基本上用这个你可以替换这样的代码 -

while (...) {
  std::cout << CostlyFn(input)) << std::endl;
}

Into this -进入这个——

OrderedThredPool<std::string> pool{10, 1};
while (...) {
  pool.Do(
    [&input] { return CostlyFn(input); },
    [](const std::string& out) {
      std::cout << out << std::endl;
    });
}

And it will execute in order.它将按顺序执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM