Skip to content

Quickstart

Integration 💻

To use the library as header-only, copy the futures subdirectory from include directory into your project.

The <futures/futures.hpp> file includes the whole library as header-only:

#include <futures/futures.hpp>

However, as you read the documentation, we recommend including only the headers for the features you are using, such as:

#include <futures/launch.hpp>

If the futures directory is not placed with your other headers files for your project, you can create a target that also looks for headers in other directories. In CMake, this can be achieved with:

add_executable(application main.cpp)
target_include_directories(application PRIVATE path/to/futures/include)

find_package(Threads)
target_link_libraries(application PRIVATE ${CMAKE_THREAD_LIBS_INIT})

target_compile_features(application PRIVATE cxx_std_14)

To manually use it as a compiled library, define the macro FUTURES_SEPARATE_COMPILATION and include the following header in exactly one new or existing source file in your project:

#ifndef FUTURES_SEPARATE_COMPILATION
#    define FUTURES_SEPARATE_COMPILATION
#endif
// In exactly *one* source file
#include <futures/impl/src.hpp>

The macro must also be set before including any other sources files in the project.

#ifndef FUTURES_SEPARATE_COMPILATION
#    define FUTURES_SEPARATE_COMPILATION
#endif
#include <futures/launch.hpp>

In general, it's easier to previously define this macro for any source file in the project. In CMake, this can be achieved with:

add_executable(application main.cpp futures-src.cpp)
target_include_directories(application PRIVATE path/to/futures/include)
target_compile_definitions(application PRIVATE FUTURES_SEPARATE_COMPILATION)
target_compile_features(application PRIVATE cxx_std_14)

find_package(Threads)
target_link_libraries(application PRIVATE ${CMAKE_THREAD_LIBS_INIT})

Check the reference for other available macros.

It's often easier to configure the project with CMake, where any required configurations will be applied automatically.

Download source:

git clone https://github.com/alandefreitas/futures/

Add add the source subdirectory in your CMake script:

add_subdirectory(path/to/futures ${CMAKE_CURRENT_BINARY_DIR}/_deps/futures)
add_executable(application main.cpp)
target_link_libraries(application PRIVATE futures::futures)

Download and include the source directly from your CMake script:

include(FetchContent)
FetchContent_Declare(futures
        GIT_REPOSITORY https://github.com/alandefreitas/futures
        GIT_TAG origin/master # or whatever tag you want
        )
FetchContent_MakeAvailable(futures)

Link to your own binaries:

add_executable(application main.cpp)
target_link_libraries(application PRIVATE futures::futures)

If you installed the library from source or with one of the packages, this project exports a CMake configuration script to be used with the find_package:

find_package(futures REQUIRED)

Or combine it with FetchContent:

include(FetchContent)
find_package(futures)
if (NOT futures_FOUND)
    FetchContent_Declare(futures
            GIT_REPOSITORY https://github.com/alandefreitas/futures
            GIT_TAG origin/master # or whatever tag you want
            )
    FetchContent_MakeAvailable(futures)
endif ()

Then link to your own binaries:

add_executable(application main.cpp)
target_link_libraries(application PRIVATE futures::futures)

If the library not installed in one of the default directories for installed software, such as /usr/local, you might need to set the CMAKE_PREFIX_PATH when running CMake:

cmake <options> -D CMAKE_PREFIX_PATH=path/that/contains/futures

Get the binary packages from the release section.

These binaries refer to the latest release version of futures.

Hint

If you need a more recent version of futures, you can download the binary packages from the CI artifacts or build the library from the source files.

We do not provide binary packages for all platforms. In that case, you can build the package from source:

Build:

cmake -S . -B build -D CMAKE_BUILD_TYPE=Release -D CMAKE_CXX_FLAGS="/O2"
cmake --build build --config Release

Install:

cmake --install build

Create packages:

cpack build

Packaging Debug and Release

Use these instructions to setup CPack to bundle multiple build directories and construct a package that contains multiple configurations of the same project.

Build:

cmake -S . -B build -D CMAKE_BUILD_TYPE=Release -D CMAKE_CXX_FLAGS="-O2"
sudo cmake --build build --config Release

Install:

sudo cmake --install build

Create packages:

sudo cpack build

Build:

cmake -S . -B build -D CMAKE_BUILD_TYPE=Release -D CMAKE_CXX_FLAGS="-O2"
cmake --build build --config Release

Install:

cmake --install build

Create packages:

cpack build

Hello world 👋

Launching Futures

cfuture<void> f1 = async([] {
    // Task 1 in default executor: a thread pool
    long_task();
});

// analogous to:
std::future<void> f2 = std::async([] {
    // Task 2 in a new thread provided by std::async.
    long_task();
});
futures::thread_pool custom_pool(1);
futures::thread_pool::executor_type ex = custom_pool.get_executor();
auto f3 = async(ex, [] {
    // Task 3 in a custom executor
    long_task();
});
auto f4 = async(ex, [](stop_token st) {
    int a = 0;
    while (!st.stop_requested()) {
        ++a;
    }
    // Task 4 stopped from another thread
    assert(a >= 0);
});
// ...
f4.request_stop();
auto f5 = schedule([] {
    // Deferred task
    long_task();
});
wait_for_all(f1, f2, f3, f4, f5);
assert(f1.is_ready());
assert(is_ready(f2));
assert(f3.is_ready());
assert(f4.is_ready());
assert(f5.is_ready());

Continuations

auto f1 = async([]() -> int { return 42; });
auto f1_cont = then(f1, [](int x) { return x * 2; });
assert(f1_cont.get() == 84);
auto f2 = std::async([]() -> int { return 63; });
auto f2_cont = f2 >> [](int x) {
    return x * 2;
};
assert(f2_cont.get() == 126);
auto f3 = std::async([]() { return std::make_tuple(1, 2.5, 'c'); });
auto f3_cont = f3 >> [](int x, double y, char z) {
    assert(x == 1);
    assert(y == 2.5);
    assert(z == 'c');
};
f3_cont.wait();

Adaptors

auto f1 = futures::async([] { long_task(); });
auto f2 = futures::async([] { long_task(); });
auto f3 = futures::async([] { long_task(); });
auto f4 = futures::async([] { long_task(); });
auto f5 = futures::when_all(f1, f2, f3, f4);
f5.wait();
auto f6 = futures::async([] {
    long_task();
    return 6;
});
auto f7 = futures::async([] {
    long_task();
    return 7;
});
auto f8 = futures::async([] {
    long_task();
    return 8;
});
auto f9 = f6 && f7 && f8;
auto f10 = futures::then(f9, [](int a, int b, int c) {
    return a * b * c;
});
assert(f10.get() == 6 * 7 * 8);
auto f1 = futures::async([]() -> int { return 10; });
auto f2 = futures::async([]() -> int { return 11; });
auto f3 = futures::async([]() -> int { return 12; });
auto f4 = futures::when_any(f1, f2, f3);
auto f5 = futures::then(f4, [](int first_ready) {
    assert(first_ready >= 10 && first_ready <= 12);
});
f5.wait();
auto f6 = futures::async([]() -> int { return 15; });
auto f7 = futures::async([]() -> int { return 16; });
auto f8 = f6 || f7;
auto r = f8.get();
if (r.index == 0) {
    assert(std::get<0>(r.tasks).get() == 15);
} else {
    assert(std::get<1>(r.tasks).get() == 16);
}

Algorithms

std::vector<int> v(50000);
std::iota(v.begin(), v.end(), 1);
assert(futures::reduce(v, 0) == 1250025000);
futures::thread_pool custom_pool(4);
futures::thread_pool::executor_type ex = custom_pool.get_executor();
futures::for_each(ex, v.begin(), v.begin() + 10, [](int x) {
    assert(x >= 0 && x <= 50000);
});
auto halve = [](auto first, auto last) {
    return std::next(first, (last - first) / 2);
};
auto it = futures::find(ex, halve, v, 3000);
if (it != v.end()) {
    assert(*it >= 0 && *it <= 50000);
    std::ptrdiff_t pos = it - v.begin();
    assert(pos >= 0 && pos <= 50000);
}

Requirements

  • Requirements: C++14
  • Tested compilers: MSVC 14.2, 14.3; GCC 5, 6, 7, 8, 9, 10, 11, 12; Clang 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14; AppleClang: 13
  • Tested standards: C++20; C++17; C++14