- new[meta header]
- std[meta namespace]
- variable[meta id-type]
- cpp17[meta cpp]
namespace std {
inline constexpr std::size_t hardware_destructive_interference_size = implementation-defined;
}
2つのオブジェクトに並行アクセスする際に、パフォーマンス低下を避けられる最小アライメントサイズ。
struct keep_apart {
std::atomic<int> cat;
std::atomic<int> dog;
};
このような構造体がある場合、cat
とdog
が同じキャッシュラインに乗ることがある。スレッド1ではcat
変数、スレッド2ではdog
変数を操作するような状況で、それぞれが共通のキャッシュを無効化してしまうパフォーマンス劣化の問題が起こりえる。こういった状況を「false sharing」という。
hardware_destructive_interference_size
は、false sharingを回避するための、変数ごとにキャッシュラインを分けられる最小アライメントサイズである。
struct keep_apart {
alignas(std::hardware_destructive_interference_size) std::atomic<int> cat;
alignas(std::hardware_destructive_interference_size) std::atomic<int> dog;
};
- std::hardware_destructive_interference_size[color ff0000]
- この変数の値は、
alignof(
max_align_t
)
以上である - 実装上、
hardware_constructive_interference_size
とhardware_destructive_interference_size
は同値になるはずだが、利用目的によって名前を使い分けるために分かれている
#include <iostream>
#include <new>
#include <thread>
#include <vector>
struct X {
alignas(std::hardware_destructive_interference_size) int a;
alignas(std::hardware_destructive_interference_size) int b;
};
struct IndividualCacheInt {
alignas(std::hardware_destructive_interference_size) int value;
};
int main()
{
std::cout << "hardware_destructive_interference_size : "
<< std::hardware_destructive_interference_size
<< std::endl;
// 構造体内のメンバ変数aとbを、それぞれ別なキャッシュラインに乗せる
{
X x;
x.a = 0;
x.b = 0;
std::thread t1{[&x]{
for (int i = 0; i < 100; ++i) {
++x.a;
}
}};
std::thread t2{[&x]{
for (int i = 0; i < 100; ++i) {
++x.b;
}
}};
t1.join();
t2.join();
}
// 連続したメモリの各要素を、個別のキャッシュに乗せる
{
std::vector<IndividualCacheInt> v{10};
std::vector<std::thread> threads;
for (std::size_t i = 0; i < v.size(); ++i) {
threads.push_back(std::thread{[&v, i]{
for (int j = 0; j < 100; ++j) {
++v[i].value;
}
}});
}
for (std::thread& t : threads) {
t.join();
}
}
}
- std::hardware_destructive_interference_size[color ff0000]
- threads.push_back[link /reference/vector/vector/push_back.md]
hardware_destructive_interference_size : 64
- C++17
- Clang: 19 [mark verified]
- GCC: 12.1 [mark verified]
- Visual C++: 2019 [mark verified]
- N4523
constexpr std::thread::hardware_{true,false}_sharing_size
- P0154R0
constexpr std::hardware_{constructive,destructive}_interference_size
- P0154R1
constexpr std::hardware_{constructive,destructive}_interference_size
- 今さら聞けないマルチプロセッサの基礎教えます ――キャッシュの共有,割り込みの共有,OSによる制御 - ページ11 キャッシュの利用にも注意が必要
- false sharingの整理 - yoskhdia’s diary
- Understanding
std::hardware_destructive_interference_size
andstd::hardware_constructive_interference_size
- Stack Overflow- 設計についての作者JF Bastien氏からのコメントがある
- WebAssemblyなどの仮想環境ではターゲットアーキテクチャが実行時に決まるため、実行時の値もあるとよいだろう、とのコメントもある
- [RFC] C++17 hardware constructive / destructive interference size - Clang Developers Mailing list