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
Definido en el encabezado <new>
inline constexpr std:: size_t
hardware_destructive_interference_size = /*implementation-defined*/ ;
(1) (desde C++17)
inline constexpr std:: size_t
hardware_constructive_interference_size = /*implementation-defined*/ ;
(2) (desde C++17)
1) Desplazamiento mínimo entre dos objetos para evitar falso compartimiento. Se garantiza que sea al menos 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) Tamaño máximo de memoria contigua para promover el true sharing. Se garantiza que sea al menos 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);

Notas

Estas constantes proporcionan una forma portátil de acceder al tamaño de línea de la caché de datos L1.

Macro de prueba de características Valor Std Característica
__cpp_lib_hardware_interference_size 201703L (C++17) constexpr std :: hardware_constructive_interference_size y

constexpr std :: hardware_destructive_interference_size

Ejemplo

El programa utiliza dos hilos que escriben atómicamente en los miembros de datos de los objetos globales dados. El primer objeto cabe en una línea de caché, lo que resulta en "interferencia de hardware". El segundo objeto mantiene sus miembros de datos en líneas de caché separadas, por lo que se evita la posible "sincronización de caché" después de las escrituras de los hilos.

#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 on 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}; // la sintonización del tiempo de referencia
struct alignas(hardware_constructive_interference_size)
OneCacheLiner // ocupa una línea de caché
{
    std::atomic_uint64_t x{};
    std::atomic_uint64_t y{};
}
oneCacheLiner;
struct TwoCacheLiner // ocupa dos líneas de caché
{
    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<double, std::milli> elapsed{now() - start};
    std::lock_guard lk{cout_mutex};
    std::cout << "oneCacheLinerThread() gastó " << 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
**Nota:** El texto no requiere traducción ya que contiene exclusivamente:
- Etiquetas HTML que deben preservarse
- Términos específicos de C++ (`std::chrono::duration`) que no deben traducirse según las instrucciones<double, std::milli> elapsed{now() - start};
    std::lock_guard lk{cout_mutex};
    std::cout << "twoCacheLinerThread() gastó " << 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
        "no está definido, use " << hardware_destructive_interference_size
                               << " como respaldo\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 << "Tiempo promedio T1: "
              << (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 << "Tiempo promedio T2: "
              << (twoCacheLiner_average / max_runs / 2) << " ms\n\n"
              << "Ratio T1/T2:~ "
              << 1.0 * oneCacheLiner_average / twoCacheLiner_average << '\n';
}

Salida posible:

__cpp_lib_hardware_interference_size = 201703
hardware_destructive_interference_size == 64
hardware_constructive_interference_size == 64
sizeof( OneCacheLiner ) == 64
sizeof( TwoCacheLiner ) == 128
oneCacheLinerThread() tardó 517.83 ms
oneCacheLinerThread() tardó 533.43 ms
oneCacheLinerThread() tardó 527.36 ms
oneCacheLinerThread() tardó 555.69 ms
oneCacheLinerThread() tardó 574.74 ms
oneCacheLinerThread() tardó 591.66 ms
oneCacheLinerThread() tardó 555.63 ms
oneCacheLinerThread() tardó 555.76 ms
Tiempo promedio T1: 550 ms
twoCacheLinerThread() tardó 89.79 ms
twoCacheLinerThread() tardó 89.94 ms
twoCacheLinerThread() tardó 89.46 ms
twoCacheLinerThread() tardó 90.28 ms
twoCacheLinerThread() tardó 89.73 ms
twoCacheLinerThread() tardó 91.11 ms
twoCacheLinerThread() tardó 89.17 ms
twoCacheLinerThread() tardó 90.09 ms
Tiempo promedio T2: 89 ms
Proporción T1/T2:~ 6.16

Véase también

devuelve el número de hilos concurrentes soportados por la implementación
(función miembro pública estática de std::thread )
devuelve el número de hilos concurrentes soportados por la implementación
(función miembro pública estática de std::jthread )