std::execution::sequenced_policy, std::execution::parallel_policy, std::execution::parallel_unsequenced_policy, std::execution::unsequenced_policy
| Definiert in Header <execution> |
||
| class sequenced_policy { /* nicht spezifiziert */ }; |
(1) | (seit C++17) |
| class parallel_policy { /* nicht spezifiziert */ }; |
(2) | (seit C++17) |
| class parallel_unsequenced_policy { /* nicht spezifiziert */ }; |
(3) | (seit C++17) |
| class unsequenced_policy { /* nicht spezifiziert */ }; |
(4) | (seit C++20) |
Während der Ausführung eines parallelen Algorithmus mit einer dieser Ausführungs-Policies wird, wenn der Aufruf einer Elementzugriffsfunktion über eine nicht abgefangene Ausnahme beendet wird, std::terminate aufgerufen, aber die Implementierungen dürfen zusätzliche Ausführungs-Policies definieren, die Ausnahmen anders behandeln.
[bearbeiten] Anmerkungen
Bei der Verwendung einer parallelen Ausführungs-Policy ist es die Verantwortung des Programmierers, Datenrennen und Deadlocks zu vermeiden.
int a[] = {0, 1}; std::vector<int> v; std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int i) { v.push_back(i * 2 + 1); // Error: data race });
std::atomic<int> x {0}; int a[] = {1, 2}; std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int) { x.fetch_add(1, std::memory_order_relaxed); while (x.load(std::memory_order_relaxed) == 1) { } // Error: assumes execution order });
int x = 0; std::mutex m; int a[] = {1, 2}; std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int) { std::lock_guard<std::mutex> guard(m); ++x; // correct });
Unsequenzierte Ausführungs-Policies sind der einzige Fall, in dem Funktionsaufrufe zueinander *unsequenziert* sind, was bedeutet, dass sie verschachtelt werden können. In allen anderen Situationen in C++ sind sie unbestimmt sequenziert (können nicht verschachtelt werden). Aus diesem Grund dürfen Benutzer bei der Verwendung dieser Policies keinen Speicher allozieren oder deallozieren, Mutexe erwerben, nicht-lockfree std::atomic-Spezialisierungen verwenden oder generell Vektorisierungs-unsichere Operationen durchführen (vektorisierungs-unsichere Funktionen sind diejenigen, die mit einer anderen Funktion synchronisieren, z. B. synchronisiert std::mutex::unlock mit dem nächsten std::mutex::lock).
int x = 0; std::mutex m; int a[] = {1, 2}; std::for_each(std::execution::par_unseq, std::begin(a), std::end(a), [&](int) { std::lock_guard<std::mutex> guard(m); // Error: lock_guard constructor calls m.lock() ++x; });
Wenn die Implementierung nicht parallelisieren oder vektorisieren kann (z. B. aufgrund fehlender Ressourcen), können alle Standard-Ausführungs-Policies auf sequenzielle Ausführung zurückfallen.
[bearbeiten] Siehe auch
| (C++17)(C++17)(C++17)(C++20) |
Globale Ausführungsrichtlinienobjekte (Konstante) |