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
Определено в заголовочном файле <new>
inline constexpr std:: size_t
hardware_destructive_interference_size = /*определяется реализацией*/ ;
(1) (начиная с C++17)
inline constexpr std:: size_t
hardware_constructive_interference_size = /*определяется реализацией*/ ;
(2) (начиная с C++17)
1) Минимальное смещение между двумя объектами для предотвращения ложного разделения. Гарантированно не менее 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) Максимальный размер смежной памяти для обеспечения истинного разделения. Гарантированно не менее 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);

Примечания

Эти константы предоставляют портативный способ доступа к размеру строки кэша данных L1.

Макрос тестирования возможностей Значение Стандарт Функция
__cpp_lib_hardware_interference_size 201703L (C++17) constexpr std :: hardware_constructive_interference_size и

constexpr std :: hardware_destructive_interference_size

Пример

Программа использует два потока, которые атомарно записывают в члены данных заданных глобальных объектов. Первый объект помещается в одну кэш-линию, что приводит к "аппаратному вмешательству". Второй объект хранит свои члены данных на отдельных кэш-линиях, благодаря чему избегается возможная "синхронизация кэша" после записи потоков.

#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 байта на 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}; // настройка времени бенчмарка
struct alignas(hardware_constructive_interference_size)
OneCacheLiner // занимает одну строку кэша
{
    std::atomic_uint64_t x{};
    std::atomic_uint64_t y{};
}
oneCacheLiner;
struct TwoCacheLiner // занимает две строки кэша
{
    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)
        если 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
(Примечание: В данном случае переводить нечего, так как текст состоит исключительно из HTML-разметки и C++ терминов, которые согласно инструкциям не подлежат переводу. Единственный возможный для перевода элемент "std::chrono::duration" является C++ специфическим термином и должен остаться без изменений.)<double, std::milli> elapsed{now() - start};
    std::lock_guard lk{cout_mutex};
    std::cout << "oneCacheLinerThread() потратил " << elapsed.count() << " мс\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
(Примечание: В данном случае переводить нечего, так как текст состоит исключительно из HTML-разметки и C++ терминологии, которая согласно инструкциям не подлежит переводу. Весь контент находится внутри HTML-тегов и содержит технические термины C++, включая пространства имен std::chrono и тип duration)<double, std::milli> elapsed{now() - start};
    std::lock_guard lk{cout_mutex};
    std::cout << "twoCacheLinerThread() потратил " << elapsed.count() << " мс\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
        "не определено, используйте " << hardware_destructive_interference_size
                               << " как резервный вариант\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 << "Среднее время T1: "
              << (oneCacheLiner_average / max_runs / 2) << " мс\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 << "Среднее время T2: "
              << (twoCacheLiner_average / max_runs / 2) << " мс\n\n"
              << "Отношение T1/T2:~ "
              << 1.0 * oneCacheLiner_average / twoCacheLiner_average << '\n';
}

Возможный вывод:

__cpp_lib_hardware_interference_size = 201703
hardware_destructive_interference_size == 64
hardware_constructive_interference_size == 64
sizeof( OneCacheLiner ) == 64
sizeof( TwoCacheLiner ) == 128
oneCacheLinerThread() занял 517.83 мс
oneCacheLinerThread() занял 533.43 мс
oneCacheLinerThread() занял 527.36 мс
oneCacheLinerThread() занял 555.69 мс
oneCacheLinerThread() занял 574.74 мс
oneCacheLinerThread() занял 591.66 мс
oneCacheLinerThread() занял 555.63 мс
oneCacheLinerThread() занял 555.76 мс
Среднее время T1: 550 мс
twoCacheLinerThread() занял 89.79 мс
twoCacheLinerThread() занял 89.94 мс
twoCacheLinerThread() занял 89.46 мс
twoCacheLinerThread() занял 90.28 мс
twoCacheLinerThread() занял 89.73 мс
twoCacheLinerThread() занял 91.11 мс
twoCacheLinerThread() занял 89.17 мс
twoCacheLinerThread() занял 90.09 мс
Среднее время T2: 89 мс
Отношение T1/T2:~ 6.16

Смотрите также

возвращает количество параллельных потоков, поддерживаемых реализацией
(публичная статическая функция-член std::thread )
возвращает количество параллельных потоков, поддерживаемых реализацией
(публичная статическая функция-член std::jthread )