Пространства имён
Варианты
Действия

std::hardware_destructive_interference_size, std::hardware_constructive_interference_size

Материал из cppreference.com
< cpp‎ | thread
 
 
Библиотека поддержки конкуренции
Ветви
(C++11)
(C++20)
(C++20)
hardware_destructive_interference_sizehardware_constructive_interference_size
(C++17)(C++17)
Пространство имён this_thread
(C++11)
(C++11)
(C++11)
Атомарные типы
(C++11)
(C++20)
Инициализация атомарных типов
(C++11)(устарело в C++20)
(C++11)(устарело в C++20)
(C++11)(устарело в C++20)
Функции освобождения для атомарных операций
Функции освобождения для атомарных флагов
Упорядочивание памяти
Взаимное исключение
(C++11)
Общее управление блокировкой
(C++11)
(C++11)
(C++11)
(C++11)(C++11)(C++11)
(C++11)
(C++11)
Условные переменные
(C++11)
Семафоры
Защёлки и барьеры
(C++20)
(C++20)
Фьючерсы
(C++11)
(C++11)
(C++11)
(C++11)
 
Определено в заголовочном файле <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 {
  // Другие элементы данных...
  alignas(sizeof(together)) together pack;
  // Другие элементы данных...
};
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)
        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() потрачено " << 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<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::cout
        << std::fixed <<