Today we are going to figure out how to create a multi-threaded application in C++11 that is capable of processing streaming data. More importantly, we won’t create any std::thread-s by ourselves, instead, we will hop on a new functional paradigm of futures and asynchronous calls.

The code of this tutorial is available on Github:

Obs01ete/async_pipeline

You can’t perform that action at this time. You signed in with another tab or window. You signed out in another tab or…

github.com

The motivation for this undertaking is that when you want to perform some heavy compute on CPU you inevitably would like to run it in multiple threads. Otherwise, the bandwidth of data grinding will be limited to one thread. For example if you have a stream of images from your web cam and you want to apply several filters to it: color adjustments, resize and maybe even some AI like say face detection, running all these processing steps may take 100s of milliseconds. With the source frame rate of 30 fps, you may get a disappointing 5–10 fps in the visualization window. Let’s see how to deal with it by means of the contents of header and stdlib.

// Here we include std::async, std::future and std::promise as our threading API.
#include <future>
// We need a data structure to manage our pipeline. The double-ended queue fits nicely.
#include <deque>
// We'd like to be able to print to console.
#include <iostream>
// And we want to measure time.
#include <chrono>

Then let’s create our processing functions func1  and func2 . In this tutorial we aren’t going to run real compute, so as a proof of concept let’s put sleeps that simulate a thread being busy.

// Let's create the first function that performs some heavy processing.
// In fact we are going to emulate processing with a sleep function
// that does not actually load a CPU core.
std::pair<size_t, std::string> func1(std::future<std::pair<size_t, std::string>>&& future_input)
{
    // Here we retrieve payload from the future object.
    // This call will block until the result is produced by another thread.
    const auto input = future_input.get();
    // Let's sleep for a while. This is to be replaced with actual compute eventually.
    std::this_thread::sleep_for(std::chrono::milliseconds(900));
    // Attach a string to input and return it to make sure that the function got executed.
    std::string output(input.second + " func1");
    // We return a regular object which will be turned into a future object by std::async.
    return std::make_pair(input.first, output);
}

// And we create another function that we are going to put into our multithreaded pipeline.
// Notice that we are passing an std::future object into it, and mark it as
// a std::move destination with &&.
std::pair<size_t, std::string> func2(std::future<std::pair<size_t, std::string>>&& future_input)
{
    // Similar to func1, but we emulate different compute time.
    const auto input = future_input.get();
    std::this_thread::sleep_for(std::chrono::milliseconds(950));
    std::string output(input.second + " func2");
    return std::make_pair(input.first, output);
}

#c++

How to build a multi-threaded pipeline in C++ with std::async
9.95 GEEK