Der kritische Abschnitt dient demselben Zweck wie das Erlangen einer Sperre (und wird wahrscheinlich intern eine Sperre verwenden).
-
std::mutex
ist eine C++-Standardfunktion, wohingegen#pragma omp critical
ist eine OpenMP-Erweiterung und nicht durch den Standard definiert. -
Die Namen der kritischen Abschnitte gelten global für das gesamte Programm (unabhängig von Modulgrenzen). Wenn Sie also einen kritischen Abschnitt mit demselben Namen in mehreren Modulen haben, können nicht zwei davon gleichzeitig ausgeführt werden. Wenn der Name weggelassen wird, wird ein Standardname angenommen. (Dokumente).
Würde Standard-C++ bevorzugen, es sei denn, es gibt einen guten Grund, das andere zu verwenden (nachdem beides gemessen wurde).
Nicht direkt auf die Frage ausgerichtet, aber es gibt noch ein weiteres Problem mit dieser Schleife:Die Sperre wird bei jeder Schleifeniteration ausgeführt. Dadurch wird die Leistung erheblich beeinträchtigt (siehe auch diese Antwort).
Ab cppreference.com
über lock_guard kann man nachlesen
und von der OpenMP
Standard über das Kritische kann man lesen:
Beide Mechanismen bieten also Mittel, um mit demselben Problem umzugehen d. h. Sicherstellung des gegenseitigen Ausschlusses eines Codeblocks.
Beides sind gröbere Locking-Mechanismen, standardmäßig jedoch OpenMP critical
ist noch gröberes Korn seit:
Wenn kein Name angegeben wird, verwenden daher alle kritischen Regionen dieselbe globale Sperre, was semantisch der Verwendung von lock_guard
entspricht mit demselben mutex
. Trotzdem kann man mit critical
mitfahren Pragma Geben Sie einen Namen an:
#pragma omp critical(name)
Angabe des name
auf einem critical
ist semantisch ähnlich der Übergabe der Sperre an std::lock_guard<std::mutex> lock(name);
.
Nichts wert ist, dass OpenMP auch explizit Sperrmechanismen wie omp_lock_t anbietet (einige Details in diesem SO-Thread).
Ungeachtet dessen sollten Sie, wann immer möglich, einen feinkörnigeren Synchronisierungsmechanismus als einen kritischen Bereich anstreben, nämlich Reduktion, Atomic oder sogar die Verwendung von Datenredundanz. Beispielsweise wäre in Ihrem Code-Snippet der leistungsfähigste Ansatz die Verwendung von reduction
gewesen Klausel, etwa so:
#pragma omp parallel for(+:someVar)
for (int i = 0; i < 1000; i++)
{
++someVar;
}
IMO sollte dies niemals eine Überlegung sein, erstens, weil kein anderer als Michael Klemm darauf hingewiesen hat:
und außerdem, wie Gilles betonte (was ich auch der gleichen Meinung war):