std:: hardware_destructive_interference_size, std:: hardware_constructive_interference_size
From cppreference.net
C++
Concurrency support library
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
헤더 파일에 정의됨
<new>
|
||
|
inline
constexpr
std::
size_t
hardware_destructive_interference_size = /*implementation-defined*/ ; |
(1) | (C++17부터) |
|
inline
constexpr
std::
size_t
hardware_constructive_interference_size = /*implementation-defined*/ ; |
(2) | (C++17부터) |
1)
거짓 공유(false sharing)를 방지하기 위한 두 객체 간의 최소 오프셋. 최소한
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 // x86-64에서 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 **변역 결과:** HTML 태그와 속성은 그대로 유지되었으며, C++ 관련 용어(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 **번역 결과:** std::chrono::duration **번역 설명:** - HTML 태그와 속성은 그대로 유지 - C++ 표준 라이브러리 용어(std::chrono::duration)는 번역하지 않음 - 태그 내의 모든 텍스트와 클래스 속성은 원본 그대로 보존<double, std::milli> elapsed{now() - start}; std::lock_guard lk{cout_mutex}; std::cout << "oneCacheLinerThread() spent " << 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 (설명: HTML 태그와 속성은 번역하지 않고, C++ 관련 용어(std::chrono::duration)는 원문을 유지하며, 태그 내부의 텍스트도 그대로 보존했습니다)<double, std::milli> elapsed{now() - start}; std::lock_guard lk{cout_mutex}; std::cout << "twoCacheLinerThread() spent " << 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 "is not defined, use " << hardware_destructive_interference_size << " as 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 << "평균 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 << "평균 T2 시간: " << (twoCacheLiner_average / max_runs / 2) << " ms\n\n" << "Ratio 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() spent 517.83 ms oneCacheLinerThread() spent 533.43 ms oneCacheLinerThread() spent 527.36 ms oneCacheLinerThread() spent 555.69 ms oneCacheLinerThread() spent 574.74 ms oneCacheLinerThread() spent 591.66 ms oneCacheLinerThread() spent 555.63 ms oneCacheLinerThread() spent 555.76 ms 평균 T1 시간: 550 ms twoCacheLinerThread() spent 89.79 ms twoCacheLinerThread() spent 89.94 ms twoCacheLinerThread() spent 89.46 ms twoCacheLinerThread() spent 90.28 ms twoCacheLinerThread() spent 89.73 ms twoCacheLinerThread() spent 91.11 ms twoCacheLinerThread() spent 89.17 ms twoCacheLinerThread() spent 90.09 ms 평균 T2 시간: 89 ms 비율 T1/T2:~ 6.16
참고 항목
|
[static]
|
구현체가 지원하는 동시 스레드 수를 반환합니다
(
std::thread
의 public static 멤버 함수)
|
|
[static]
|
구현체가 지원하는 동시 스레드 수를 반환합니다
(
std::jthread
의 public static 멤버 함수)
|