Unterschied zwischen std::lock_guard und #pragma omp kritisch

Unterschied zwischen std::lock_guard und #pragma omp kritisch

Der kritische Abschnitt dient demselben Zweck wie das Erlangen einer Sperre (und wird wahrscheinlich intern eine Sperre verwenden).

  1. std::mutex ist eine C++-Standardfunktion, wohingegen #pragma omp critical ist eine OpenMP-Erweiterung und nicht durch den Standard definiert.

  2. 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):