Namensräume
Varianten
Aktionen

std::execution::sequenced_policy, std::execution::parallel_policy, std::execution::parallel_unsequenced_policy, std::execution::unsequenced_policy

Von cppreference.com
< cpp‎ | algorithm
 
 
Algorithmenbibliothek
Beschränkte Algorithmen und Algorithmen für Bereiche (C++20)
Beschränkte Algorithmen, z.B. ranges::copy, ranges::sort, ...
Ausführungsrichtlinien (C++17)
execution::sequenced_policyexecution::parallel_policyexecution::parallel_unsequenced_policyexecution::parallel_unsequenced
(C++17)(C++17)(C++17)(C++20)
Nicht-modifizierende Sequenzoperationen
Stapeloperationen
(C++17)
Suchoperationen
(C++11)                (C++11)(C++11)

Modifizierende Sequenzoperationen
Kopieroperationen
(C++11)
(C++11)
Tauschoperationen
Transformationsoperationen
Generierungsoperationen
Entfernungsoperationen
Ordnungsändernde Operationen
(bis C++17)(C++11)
(C++20)(C++20)
Stichprobenoperationen
(C++17)

Sortier- und verwandte Operationen
Partitionierungsoperationen
Sortieroperationen
Binäre Suchoperationen
(auf partitionierten Bereichen)
Mengenoperationen (auf sortierten Bereichen)
Zusammenführungsoperationen (auf sortierten Bereichen)
Heapoperationen
Minimum/Maximum-Operationen
(C++11)
(C++17)
Lexikographische Vergleichsoperationen
Permutationsoperationen
C-Bibliothek
Numerische Operationen
Operationen auf uninitialisiertem Speicher
 
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)
1) Der Ausführungs-Policy-Typ, der als eindeutiger Typ verwendet wird, um Überladungen von parallelen Algorithmen zu unterscheiden und zu verlangen, dass die Ausführung eines parallelen Algorithmus nicht parallelisiert werden darf. Die Aufrufe von Elementzugriffsfunktionen in parallelen Algorithmen, die mit dieser Policy aufgerufen werden (üblicherweise als std::execution::seq angegeben), sind im aufrufenden Thread unbestimmt sequenziert.
2) Der Ausführungs-Policy-Typ, der als eindeutiger Typ verwendet wird, um Überladungen von parallelen Algorithmen zu unterscheiden und anzuzeigen, dass die Ausführung eines parallelen Algorithmus parallelisiert werden darf. Die Aufrufe von Elementzugriffsfunktionen in parallelen Algorithmen, die mit dieser Policy aufgerufen werden (üblicherweise als std::execution::par angegeben), dürfen entweder im aufrufenden Thread oder in einem von der Bibliothek implizit erstellten Thread zur Unterstützung der parallelen Ausführung von Algorithmen ausgeführt werden. Alle solchen Aufrufe, die im selben Thread ausgeführt werden, sind zueinander unbestimmt sequenziert. Wenn die von std::thread oder std::jthread erstellten Ausführungs-Threads parallele Vorwärtsfortschrittsgarantien bieten, dann bieten die von der Bibliothek erstellten Ausführungs-Threads parallele Vorwärtsfortschrittsgarantien. Andernfalls ist die bereitgestellte Vorwärtsfortschrittsgarantie implementierungsabhängig. Hinweis: Parallele Vorwärtsfortschrittsgarantien bedeuten, dass, wenn ein Ausführungs-Thread einen Schritt macht, er schließlich einen weiteren Schritt machen wird, was es den Threads ermöglicht, kritische Abschnitte zu betreten und Sperren zu erhalten, da der Thread, der die Sperre hält, schließlich wieder geplant wird und sie freigeben kann.
3) Der Ausführungs-Policy-Typ, der als eindeutiger Typ verwendet wird, um Überladungen von parallelen Algorithmen zu unterscheiden und anzuzeigen, dass die Ausführung eines parallelen Algorithmus parallelisiert, vektorisiert oder über Threads migriert werden darf (z. B. durch einen Parent-Stealing-Scheduler). Die Aufrufe von Elementzugriffsfunktionen in parallelen Algorithmen, die mit dieser Policy aufgerufen werden, dürfen in unsortierter Weise in nicht spezifizierten Threads ausgeführt werden und sind untereinander innerhalb jedes Threads unsequenziert. Der Aufruf von Elementzugriffsfunktionen in parallelen Algorithmen, die mit dieser Policy aufgerufen werden, darf keine Vektorisierungs-unsicheren Operationen aufrufen, wie z. B. diejenigen, die von der Standardbibliothek zur Synchronisation spezifiziert werden, einschließlich derer von std::atomic und anderen Nebenläufigkeitsprimitiven. Wenn die von std::thread oder std::jthread erstellten Ausführungs-Threads parallele Vorwärtsfortschrittsgarantien bieten, dann bieten die von der Bibliothek erstellten Ausführungs-Threads schwach-parallele Vorwärtsfortschrittsgarantien. Andernfalls ist die bereitgestellte Vorwärtsfortschrittsgarantie die des Threads, der den parallelen Algorithmus aufruft. Hinweis: Schwach-parallele Vorwärtsfortschrittsgarantien bedeuten, dass einer der Ausführungs-Threads, die einen Schritt gemacht haben, schließlich einen weiteren Schritt machen wird, was es den Threads nicht erlaubt, kritische Abschnitte zu betreten oder Sperren zu erhalten, da der Thread, der die Sperre hält, möglicherweise nicht wieder geplant wird, bis ein Thread, der versucht, die Sperre zu erhalten, beendet wurde.
4) Der Ausführungs-Policy-Typ, der als eindeutiger Typ verwendet wird, um Überladungen von parallelen Algorithmen zu unterscheiden und anzuzeigen, dass die Ausführung eines parallelen Algorithmus vektorisiert werden darf, z. B. auf einem einzigen Thread unter Verwendung von Anweisungen, die auf mehreren Datenelementen operieren.

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) [edit]