Skip to content

Latest commit

 

History

History
150 lines (107 loc) · 3.46 KB

File metadata and controls

150 lines (107 loc) · 3.46 KB

Lock-Free Programming

Zurück


Inhalt


Verwendete Werkzeuge

Klassen:

  • Klasse std::atomic

Quellcode

LockFreeProgramming01.cpp
LockFreeProgramming02.cpp.


CAS / Compare-and-Swap-Idiom

Die beiden Methoden compare_exchange_weak / compare_exchange_strong (auch als CAS / Compare-and-Swap-Idiom bezeichnet) führen eine atomare Anweisung aus, die zur Synchronisierung verwendet wird.

Sie vergleicht den Inhalt eines Speicherorts mit einem gegebenen (dem vorherigen) Wert und ändert den Inhalt dieses Speicherorts nur bei Übereinstimmung auf einen neuen gegebenen Wert.

Dies geschieht als einzelne atomare Operation.

Die Atomizität garantiert, dass der neue Wert auf Basis aktueller Informationen berechnet wird. Wäre der Wert in der Zwischenzeit von einem anderen Thread aktualisiert worden, würde der Schreibvorgang fehlschlagen.

Das Ergebnis der Operation, gegeben durch einen booleschen Rückgabewert, gibt an, ob die Ersetzung durchgeführt wurde oder nicht.


Zwei Beispiele

Erstes Beispiel: Erfolgreiche Ausführung

01: void test ()
02: {
03:     std::atomic<int> value{ 123 };
04: 
05:     int expectedValue = 123;
06: 
07:     std::println("Previous expected value: {}", expectedValue);
08: 
09:     bool b = value.compare_exchange_weak(expectedValue, 456);
10: 
11:     std::println("Return Value:            {}", b);
12:     std::println("Current expected Value:  {}", expectedValue);
13:     std::println("Current Value:           {}", value.load());
14: }

Ausgabe:

Previous expected value: 123
Return Value:            true
Current expected Value:  123
Current Value:           456

Zweites Beispiel: Erfolglose Ausführung

01: void test()
02: {
03:     std::atomic<int> value{ 123 };
04: 
05:     int expectedValue = 124;
06: 
07:     std::println("Previous expected value: {}", expectedValue);
08: 
09:     bool b = value.compare_exchange_weak(expectedValue, 456);
10: 
11:     std::println("Return Value:            {}", b);
12:     std::println("Current expected Value:  {}", expectedValue);
13:     std::println("Current Value:           {}", value.load());
14:     std::println();
15: }

Ausgabe:

Previous expected value: 124
Return Value:            false
Current expected Value:  123             // <=== note this value !!!
Current Value:           123

Ein Vergleich: Atomares Inkrement versus CAS

Die atomare Inkrement-Operation kann man auch mit einer CAS-Anweisung formulieren. Die folgenden beiden Code-Fragment sind bzgl. ihrer Funktionalität identisch:

std::atomic<long> count{};
...
++count;

und

std::atomic<long> count{};
...
T value{ count.load(std::memory_order_relaxed) };

while (!count.compare_exchange_weak(
    value,
    value + 1,
    std::memory_order_release,
    std::memory_order_relaxed))
{
}

Literaturhinweise

Einen weiterführenden Artikel mit dem Thema „An Introduction to Lock-Free Programming” findet man hier.


Zurück