C++17stladvanced
Parallel Algorithms (std::execution::seq / par / par_unseq)
C++17 · Practical Modern · Compiler flag: -std=c++17
Explanation
C++17 adds execution policies to over 60 existing STL algorithms (sort, for_each, transform, find, count, etc.). `seq` runs sequentially, `par` allows parallel execution across threads, and `par_unseq` additionally allows vectorized (SIMD) execution within threads.
Real-World Scenario
Sort a multi-million-row dataset in a data analytics pipeline using all available CPU cores.
Quick Snippet
snippet.cpp
#include <algorithm>
#include <execution>
#include <vector>
std::vector<int> data(10'000'000);
// ... fill data ...
std::sort(std::execution::par, data.begin(), data.end());
auto it = std::find(std::execution::par, data.begin(), data.end(), 42);
std::for_each(std::execution::par_unseq, data.begin(), data.end(),
[](int& x) { x *= 2; });Full Example
parallel_algorithms.cpp
// CodeNebula - C++17 Example: Parallel Algorithms (Execution Policies)
// Compile: g++ -std=c++17 -Wall -Wextra -o example parallel_algorithms.cpp -ltbb
// Note: Parallel execution requires a threading backend (e.g., Intel TBB).
// Without TBB, std::execution::seq still works. par/par_unseq may need TBB linked.
// C++17 adds execution policies to many <algorithm> and <numeric> functions:
// seq (sequential), par (parallel), par_unseq (parallel + vectorized).
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <execution>
#include <chrono>
int main() {
// --- Execution policy overview ---
std::cout << "=== Execution policies ===" << std::endl;
std::cout << "seq: sequential, single-threaded" << std::endl;
std::cout << "par: parallel, multi-threaded" << std::endl;
std::cout << "par_unseq: parallel + vectorized (SIMD)" << std::endl;
const int N = 1'000'000;
std::vector<int> data(N);
std::iota(data.begin(), data.end(), 1); // 1, 2, ..., N
// --- std::sort with execution policy ---
std::cout << "\n=== Parallel sort ===" << std::endl;
std::vector<int> to_sort(data.rbegin(), data.rend()); // reversed
std::sort(std::execution::seq, to_sort.begin(), to_sort.end());
std::cout << "Sorted (seq): first=" << to_sort.front()
<< ", last=" << to_sort.back() << std::endl;
// --- std::for_each with parallel policy ---
std::cout << "\n=== Parallel for_each ===" << std::endl;
std::vector<double> squares(N);
std::for_each(std::execution::seq, data.begin(), data.end(),
[&squares](int x) { squares[x - 1] = static_cast<double>(x) * x; });
std::cout << "squares[0]=" << squares[0]
<< ", squares[999999]=" << squares[999999] << std::endl;
// --- std::transform with seq policy ---
std::cout << "\n=== Parallel transform ===" << std::endl;
std::vector<int> doubled(N);
std::transform(std::execution::seq, data.begin(), data.end(),
doubled.begin(), [](int x) { return x * 2; });
std::cout << "doubled[0]=" << doubled[0]
<< ", doubled[4]=" << doubled[4] << std::endl;
// --- std::reduce (parallel-friendly accumulation) ---
std::cout << "\n=== std::reduce ===" << std::endl;
long long sum_seq = std::reduce(std::execution::seq,
data.begin(), data.end(), 0LL);
std::cout << "Sum (seq): " << sum_seq << std::endl;
std::cout << "Expected: " << (static_cast<long long>(N) * (N + 1) / 2) << std::endl;
// --- std::count_if ---
std::cout << "\n=== Parallel count_if ===" << std::endl;
auto evens = std::count_if(std::execution::seq,
data.begin(), data.end(), [](int x) { return x % 2 == 0; });
std::cout << "Even numbers: " << evens << std::endl;
// --- std::find_if ---
std::cout << "\n=== Parallel find_if ===" << std::endl;
auto it = std::find_if(std::execution::seq,
data.begin(), data.end(), [](int x) { return x > 999990; });
if (it != data.end()) {
std::cout << "First > 999990: " << *it << std::endl;
}
// --- std::any_of / all_of / none_of ---
std::cout << "\n=== Parallel predicates ===" << std::endl;
bool has_neg = std::any_of(std::execution::seq,
data.begin(), data.end(), [](int x) { return x < 0; });
bool all_pos = std::all_of(std::execution::seq,
data.begin(), data.end(), [](int x) { return x > 0; });
std::cout << "any negative: " << has_neg << std::endl;
std::cout << "all positive: " << all_pos << std::endl;
return 0;
}
/*
Expected output:
=== Execution policies ===
seq: sequential, single-threaded
par: parallel, multi-threaded
par_unseq: parallel + vectorized (SIMD)
=== Parallel sort ===
Sorted (seq): first=1, last=1000000
=== Parallel for_each ===
squares[0]=1, squares[999999]=1e+12
=== Parallel transform ===
doubled[0]=2, doubled[4]=10
=== std::reduce ===
Sum (seq): 500000500000
Expected: 500000500000
=== Parallel count_if ===
Even numbers: 500000
=== Parallel find_if ===
First > 999990: 999991
=== Parallel predicates ===
any negative: 0
all positive: 1
*/
Run command
g++ -std=c++17 -Wall -Wextra -o example parallel_algorithms.cpp -ltbb