Namespaces
Variants

std:: hardware_destructive_interference_size, std:: hardware_constructive_interference_size

From cppreference.net
Concurrency support library
Threads
(C++11)
(C++20)
hardware_destructive_interference_size hardware_constructive_interference_size
(C++17) (C++17)
this_thread namespace
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
Generic lock management
Condition variables
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
Safe reclamation
Hazard pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11) (deprecated in C++20)
(C++11) (deprecated in C++20)
Memory ordering
(C++11) (deprecated in C++26)
Free functions for atomic operations
Free functions for atomic flags
Definiert im Header <new>
inline constexpr std:: size_t
hardware_destructive_interference_size = /*implementation-defined*/ ;
(1) (seit C++17)
inline constexpr std:: size_t
hardware_constructive_interference_size = /*implementation-defined*/ ;
(2) (seit C++17)
1) Mindestabstand zwischen zwei Objekten zur Vermeidung von False Sharing. Garantiert mindestens alignof ( std:: max_align_t )
struct keep_apart
{
    alignas(std::hardware_destructive_interference_size) std::atomic<int> cat;
    alignas(std::hardware_destructive_interference_size) std::atomic<int> dog;
};
2) Maximale Größe zusammenhängenden Speichers zur Förderung von True Sharing. Garantiert mindestens alignof ( std:: max_align_t )
struct together
{
    std::atomic<int> dog;
    int puppy;
};
struct kennel
{
    // Other data members...
    alignas(sizeof(together)) together pack;
    // Other data members...
};
static_assert(sizeof(together) <= std::hardware_constructive_interference_size);

Hinweise

Diese Konstanten bieten eine portable Möglichkeit, auf die L1-Daten-Cache-Zeilengröße zuzugreifen.

Feature-Test Makro Wert Std Funktion
__cpp_lib_hardware_interference_size 201703L (C++17) constexpr std :: hardware_constructive_interference_size und

constexpr std :: hardware_destructive_interference_size

Beispiel

Das Programm verwendet zwei Threads, die atomar in die Datenmitglieder der gegebenen globalen Objekte schreiben. Das erste Objekt passt in eine Cache-Zeile, was zu "Hardware Interference" führt. Das zweite Objekt hält seine Datenmitglieder auf separaten Cache-Zeilen, wodurch mögliche "Cache-Synchronisierung" nach Thread-Schreibvorgängen vermieden wird.

#include <atomic>
#include <chrono>
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <new>
#include <thread>
#ifdef __cpp_lib_hardware_interference_size
    using std::hardware_constructive_interference_size;
    using std::hardware_destructive_interference_size;
#else
    // 64 Bytes auf x86-64 │ L1_CACHE_BYTES │ L1_CACHE_SHIFT │ __cacheline_aligned │ ...
    constexpr std::size_t hardware_constructive_interference_size = 64;
    constexpr std::size_t hardware_destructive_interference_size = 64;
#endif
std::mutex cout_mutex;
constexpr int max_write_iterations{10'000'000}; // die Benchmark-Zeitabstimmung
struct alignas(hardware_constructive_interference_size)
OneCacheLiner // belegt eine Cache-Zeile
{
    std::atomic_uint64_t x{};
    std::atomic_uint64_t y{};
}
oneCacheLiner;
struct TwoCacheLiner // belegt zwei Cache-Zeilen
{
    alignas(hardware_destructive_interference_size) std::atomic_uint64_t x{};
    alignas(hardware_destructive_interference_size) std::atomic_uint64_t y{};
}
twoCacheLiner;
inline auto now() noexcept { return std::chrono::high_resolution_clock::now(); }
template<bool xy>
void oneCacheLinerThread()
{
    const auto start{now()};
    for (uint64_t count{}; count != max_write_iterations; ++count)
        if constexpr (xy)
            oneCacheLiner.x.fetch_add(1, std::memory_order_relaxed);
        else
            oneCacheLiner.y.fetch_add(1, std::memory_order_relaxed);
    const std::chrono::duration
(Anmerkung: Der Text enthält nur C++-spezifische Begriffe und HTML-Tags, die gemäß den Anweisungen nicht übersetzt werden müssen. Daher bleibt die Ausgabe identisch mit der Eingabe.)<double, std::milli> elapsed{now() - start};
    std::lock_guard lk{cout_mutex};
    std::cout << "oneCacheLinerThread() verbrachte " << elapsed.count() << " ms\n";
    if constexpr (xy)
        oneCacheLiner.x = elapsed.count();
    else
        oneCacheLiner.y = elapsed.count();
}
template<bool xy>
void twoCacheLinerThread()
{
    const auto start{now()};
    for (uint64_t count{}; count != max_write_iterations; ++count)
        if constexpr (xy)
            twoCacheLiner.x.fetch_add(1, std::memory_order_relaxed);
        else
            twoCacheLiner.y.fetch_add(1, std::memory_order_relaxed);
    const std::chrono::duration
*Hinweis: Der Text innerhalb der HTML-Tags wurde nicht übersetzt, da es sich um C++-spezifische Begriffe handelt, die gemäß den Anweisungen unverändert bleiben sollen.*<double, std::milli> elapsed{now() - start};
    std::lock_guard lk{cout_mutex};
    std::cout << "twoCacheLinerThread() verbrachte " << elapsed.count() << " ms\n";
    if constexpr (xy)
        twoCacheLiner.x = elapsed.count();
    else
        twoCacheLiner.y = elapsed.count();
}
int main()
{
    std::cout << "__cpp_lib_hardware_interference_size "
#   ifdef __cpp_lib_hardware_interference_size
        "= " << __cpp_lib_hardware_interference_size << '\n';
#   else
        "ist nicht definiert, verwenden Sie " << hardware_destructive_interference_size
                               << " als Fallback\n";
#   endif
    std::cout << "hardware_destructive_interference_size == "
              << hardware_destructive_interference_size << '\n'
              << "hardware_constructive_interference_size == "
              << hardware_constructive_interference_size << "\n\n"
              << std::fixed << std::setprecision(2)
              << "sizeof( OneCacheLiner ) == " << sizeof(OneCacheLiner) << '\n'
              << "sizeof( TwoCacheLiner ) == " << sizeof(TwoCacheLiner) << "\n\n";
    constexpr int max_runs{4};
    int oneCacheLiner_average{0};
    for (auto i{0}; i != max_runs; ++i)
    {
        std::thread th1{oneCacheLinerThread<0>};
        std::thread th2{oneCacheLinerThread<1>};
        th1.join();
        th2.join();
        oneCacheLiner_average += oneCacheLiner.x + oneCacheLiner.y;
    }
    std::cout << "Durchschnittliche T1-Zeit: "
              << (oneCacheLiner_average / max_runs / 2) << " ms\n\n";
    int twoCacheLiner_average{0};
    for (auto i{0}; i != max_runs; ++i)
    {
        std::thread th1{twoCacheLinerThread<0>};
        std::thread th2{twoCacheLinerThread<1>};
        th1.join();
        th2.join();
        twoCacheLiner_average += twoCacheLiner.x + twoCacheLiner.y;
    }
    std::cout << "Durchschnittliche T2-Zeit: "
              << (twoCacheLiner_average / max_runs / 2) << " ms\n\n"
              << "Verhältnis T1/T2:~ "
              << 1.0 * oneCacheLiner_average / twoCacheLiner_average << '\n';
}

Mögliche Ausgabe:

__cpp_lib_hardware_interference_size = 201703
hardware_destructive_interference_size == 64
hardware_constructive_interference_size == 64
sizeof( OneCacheLiner ) == 64
sizeof( TwoCacheLiner ) == 128
oneCacheLinerThread() benötigte 517,83 ms
oneCacheLinerThread() benötigte 533,43 ms
oneCacheLinerThread() benötigte 527,36 ms
oneCacheLinerThread() benötigte 555,69 ms
oneCacheLinerThread() benötigte 574,74 ms
oneCacheLinerThread() benötigte 591,66 ms
oneCacheLinerThread() benötigte 555,63 ms
oneCacheLinerThread() benötigte 555,76 ms
Durchschnittliche T1-Zeit: 550 ms
twoCacheLinerThread() benötigte 89,79 ms
twoCacheLinerThread() benötigte 89,94 ms
twoCacheLinerThread() benötigte 89,46 ms
twoCacheLinerThread() benötigte 90,28 ms
twoCacheLinerThread() benötigte 89,73 ms
twoCacheLinerThread() benötigte 91,11 ms
twoCacheLinerThread() benötigte 89,17 ms
twoCacheLinerThread() benötigte 90,09 ms
Durchschnittliche T2-Zeit: 89 ms
Verhältnis T1/T2:~ 6,16

Siehe auch

gibt die Anzahl der gleichzeitig unterstützten Threads durch die Implementierung zurück
(öffentliche statische Memberfunktion von std::thread )
gibt die Anzahl der gleichzeitig unterstützten Threads durch die Implementierung zurück
(öffentliche statische Memberfunktion von std::jthread )