从基于线程的流水线技术转向基于任务的并行性? (C ++)

时间:2015-01-08 14:36:12

标签: c++ multithreading parallel-processing

我正在研究如何将一些现有的C ++代码从基于线程的迁移迁移到基于任务的并行性,以及是否需要迁移。这是我的情景:

假设我有一些函数可以在事件上执行。假设我有一个摄像头,每次一帧到达时我想做一些繁重的处理并保存结果。一些处理是串行的,所以如果我只是在同一个线程中串行处理每个帧,我就不会获得完整的CPU利用率。假设帧每33毫秒到达一帧,帧的处理延迟接近100毫秒。

因此,在我当前的实现中,我创建了3个线程来处理帧并将每个新帧分配给循环中的这些工作线程之一。因此,线程T0可能会处理帧F0,F3,F6等。现在我获得了完整的CPU利用率,并且我不必丢帧以保持实时速率。

由于处理需要各种大的临时资源,我可以为每个工作线程预先分配这些资源。因此,不必为每一帧重新分配它们。这种每线程资源的策略适用于粒度:如果它们是按帧分配的,这将花费太长时间,但是如果有更多的工作线程,我们就会耗尽资源。

我没有看到使用标准C ++ 11或Microsoft的PPL库将这种基于线程的并行性替换为基于任务的并行性的方法。如果有这样做的模式可以在下面勾勒出来,我会非常乐意学习它。

问题是存储状态的位置 - 分配的临时资源(例如GPU内存) - 可以重复用于后续帧,但不得与当前处理帧的资源冲突。

在这种情况下,是否甚至需要迁移到基于任务的并行性?

1 个答案:

答案 0 :(得分:0)

我想出来了。这是一个示例解决方案:

#include <iostream>
#include <ppltasks.h>
#include <thread>
#include <vector>

using PipelineState = int;
using PipelineStateArg = std::shared_ptr<PipelineState>;
using FrameState = int;
struct Pipeline
{
    PipelineStateArg state;
    concurrency::task<void> task;
};
std::vector<Pipeline> pipelines;

void proc(const FrameState& fs, PipelineState& ps)
{ 
    std::cout << "Process frame " << fs << " in pipeline " << ps << std::endl; 
}

void on_frame(int index)
{
    FrameState frame = index;
    if (index < 2)
    {
        // Start a new pipeline
        auto state = std::make_shared<PipelineState>(index);
        pipelines.push_back({state, concurrency::create_task([=]() 
        { 
            proc(frame, *state); 
        })});
    }
    else
    {
        // Use an existing pipeline
        auto& pipeline = pipelines[index & 1];
        auto state = pipeline.state;
        pipeline.task = pipeline.task.then([=]() 
        { 
            proc(frame, *state); 
        });
    }
}

void main()
{
    for (int i = 0; i < 100; ++i)
    {
        on_frame(i);
        std::this_thread::sleep_for(std::chrono::milliseconds(33));
    }
    for (auto& pipeline : pipelines)
        pipeline.tail.wait();
}