Namensräume
Varianten
Aktionen

std::atomic_thread_fence

Von cppreference.com
< cpp‎ | atomic
 
 
Bibliothek für nebenläufige Programmierung
Threads
(C++11)
(C++20)
this_thread Namespace
(C++11)
(C++11)
(C++11)
Kooperatives Beenden
Gegenseitiger Ausschluss
(C++11)
Allgemeines Sperrungsmanagement
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
Bedingungsvariablen
(C++11)
Semaphoren
Latches und Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
(C++11)
Sichere Wiederherstellung
(C++26)
Hazard Pointer
Atomare Typen
(C++11)
(C++20)
Initialisierung von atomaren Typen
(C++11)(veraltet in C++20)
(C++11)(veraltet in C++20)
Speicherordnung
(C++11)(deprecated in C++26)
atomic_thread_fence
(C++11)
Freie Funktionen für atomare Operationen
Freie Funktionen für atomare Flags
 
Definiert in Header <atomic>
extern "C" void atomic_thread_fence( std::memory_order order ) noexcept;
(seit C++11)

Stellt Speichersynchronisierungsreihenfolge für nicht-atomare und relaxierte atomare Zugriffe her, wie durch order angewiesen, ohne eine zugehörige atomare Operation. Beachten Sie jedoch, dass mindestens eine atomare Operation erforderlich ist, um die Synchronisation einzurichten, wie unten beschrieben.

Inhalt

[bearbeiten] Fence-atomare Synchronisation

Ein Release-Fence F im Thread A synchronisiert sich mit einer atomaren Acquire-Operation Y im Thread B, wenn

  • eine atomare Schreiboperation X existiert (mit beliebiger Speicherreihenfolge),
  • Y den von X geschriebenen Wert liest (oder den Wert, der von einer Release-Sequenz, die von X angeführt wird, geschrieben worden wäre, wenn X eine Release-Operation wäre),
  • F vor X im Thread A sequenziert ist.

In diesem Fall werden alle nicht-atomaren und relaxierten atomaren Schreiboperationen, die in Thread A vor F sequenziert sind, alle nicht-atomaren und relaxierten atomaren Leseoperationen von denselben Speicherstellen, die in Thread B nach Y vorgenommen werden, vorangehen.

[bearbeiten] Atomar-Fence-Synchronisation

Eine atomare Release-Operation X im Thread A synchronisiert sich mit einem Acquire-Fence F im Thread B, wenn

In diesem Fall werden alle nicht-atomaren und relaxierten atomaren Schreiboperationen, die in Thread A vor X sequenziert sind, alle nicht-atomaren und relaxierten atomaren Leseoperationen von denselben Speicherstellen, die in Thread B nach F vorgenommen werden, vorangehen.

[bearbeiten] Fence-Fence-Synchronisation

Ein Release-Fence FA im Thread A synchronisiert sich mit einem Acquire-Fence FB im Thread B, wenn

  • ein atomares Objekt M existiert,
  • eine atomare Schreiboperation X existiert (mit beliebiger Speicherreihenfolge), die M im Thread A modifiziert,
  • FA vor X im Thread A sequenziert ist,
  • eine atomare Leseoperation Y existiert (mit beliebiger Speicherreihenfolge) im Thread B,
  • Y den von X geschriebenen Wert liest (oder den Wert, der von einer Release-Sequenz, die von X angeführt wird, geschrieben worden wäre, wenn X eine Release-Operation wäre),
  • Y vor FB im Thread B sequenziert ist.

In diesem Fall werden alle nicht-atomaren und relaxierten atomaren Schreiboperationen, die in Thread A vor FA sequenziert sind, alle nicht-atomaren und relaxierten atomaren Leseoperationen von denselben Speicherstellen, die in Thread B nach FB vorgenommen werden, vorangehen.

[bearbeiten] Parameter

Reihenfolge - die von diesem Fence ausgeführte Speicherreihenfolge

[bearbeiten] Rückgabewert

(keine)

[bearbeiten] Anmerkungen

Auf x86 (einschließlich x86-64) geben atomic_thread_fence-Funktionen keine CPU-Instruktionen aus und beeinflussen nur die Kompilierzeit-Codebewegung, außer für std::atomic_thread_fence(std::memory_order_seq_cst).

atomic_thread_fence legt stärkere Synchronisationsbeschränkungen fest als eine atomare Schreiboperation mit derselben std::memory_order. Während eine atomare Store-Release-Operation alle vorhergehenden Lese- und Schreibvorgänge daran hindert, sich nach der Store-Release zu bewegen, verhindert ein atomic_thread_fence mit std::memory_order_release-Reihenfolge, dass alle vorhergehenden Lese- und Schreibvorgänge sich nach allen nachfolgenden Schreibvorgängen bewegen.

Fence-Fence-Synchronisation kann verwendet werden, um einer Sequenz mehrerer relaxierter atomarer Operationen eine Synchronisation hinzuzufügen, zum Beispiel

// Global
std::string computation(int);
void print(std::string);
 
std::atomic<int> arr[3] = {-1, -1, -1};
std::string data[1000]; //non-atomic data
 
// Thread A, compute 3 values.
void ThreadA(int v0, int v1, int v2)
{
//  assert(0 <= v0, v1, v2 < 1000);
    data[v0] = computation(v0);
    data[v1] = computation(v1);
    data[v2] = computation(v2);
    std::atomic_thread_fence(std::memory_order_release);
    std::atomic_store_explicit(&arr[0], v0, std::memory_order_relaxed);
    std::atomic_store_explicit(&arr[1], v1, std::memory_order_relaxed);
    std::atomic_store_explicit(&arr[2], v2, std::memory_order_relaxed);
}
 
// Thread B, prints between 0 and 3 values already computed.
void ThreadB()
{
    int v0 = std::atomic_load_explicit(&arr[0], std::memory_order_relaxed);
    int v1 = std::atomic_load_explicit(&arr[1], std::memory_order_relaxed);
    int v2 = std::atomic_load_explicit(&arr[2], std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_acquire);
//  v0, v1, v2 might turn out to be -1, some or all of them.
//  Otherwise it is safe to read the non-atomic data because of the fences:
    if (v0 != -1)
        print(data[v0]);
    if (v1 != -1)
        print(data[v1]);
    if (v2 != -1)
        print(data[v2]);
}

[bearbeiten] Beispiel

Durchsuchen Sie ein Array von Postfächern und verarbeiten Sie nur die, die für uns bestimmt sind, ohne unnötige Synchronisation. Dieses Beispiel verwendet atomare Fence-Synchronisation.

const int num_mailboxes = 32;
std::atomic<int> mailbox_receiver[num_mailboxes];
std::string mailbox_data[num_mailboxes];
 
// The writer threads update non-atomic shared data 
// and then update mailbox_receiver[i] as follows:
mailbox_data[i] = ...;
std::atomic_store_explicit(&mailbox_receiver[i], receiver_id, std::memory_order_release);
 
// Reader thread needs to check all mailbox[i], but only needs to sync with one.
for (int i = 0; i < num_mailboxes; ++i)
    if (std::atomic_load_explicit(&mailbox_receiver[i],
        std::memory_order_relaxed) == my_id)
    {
        // synchronize with just one writer
        std::atomic_thread_fence(std::memory_order_acquire);
        // guaranteed to observe everything done in the writer thread
        // before the atomic_store_explicit()
        do_work(mailbox_data[i]);
    }

[bearbeiten] Siehe auch

definiert Speicherordnungseinschränkungen für die gegebene atomare Operation
(Enum) [bearbeiten]
Fence zwischen einem Thread und einem Signal-Handler, der im selben Thread ausgeführt wird
(Funktion) [bearbeiten]
C-Dokumentation für atomic_thread_fence