我最近在我的应用程序中遇到了我认为是错误共享的问题,并且我已经查询了Sutter's article如何将数据与缓存行对齐。他建议使用以下C ++代码:
// C++ (using C++0x alignment syntax)
template<typename T>
struct cache_line_storage {
[[ align(CACHE_LINE_SIZE) ]] T data;
char pad[ CACHE_LINE_SIZE > sizeof(T)
? CACHE_LINE_SIZE - sizeof(T)
: 1 ];
};
我可以看到当CACHE_LINE_SIZE > sizeof(T)
为真时这将如何工作 - 结构cache_line_storage
最终会占用一个完整的内存缓存行。但是,当sizeof(T)
大于单个缓存行时,我认为我们应该将数据填充CACHE_LINE_SIZE - T % CACHE_LINE_SIZE
个字节,以便生成的结构的大小是缓存的整数倍线条大小。我的理解有什么问题?为什么填充1个字节就足够了?
答案 0 :(得分:7)
您不能拥有大小为0的数组,因此需要1才能进行编译。但是,该规范的当前草案版本说这种填充是不必要的;编译器必须填充结构的对齐方式。
另请注意,如果CACHE_LINE_SIZE
小于alignof(T)
,则此代码格式错误。要解决此问题,您应该使用[[align(CACHE_LINE_SIZE), align(T)]]
,这将确保永远不会选择较小的对齐方式。
答案 1 :(得分:3)
想象
#define CACHE_LINE_SIZE 32
sizeof(T) == 48
现在,考虑[[ align(CACHE_LINE_SIZE) ]]
的工作原理。例如:
[[ align(32) ]] Foo foo;
这将迫使某些sizeof(Foo) == 32n
n
。例如,如果需要,对齐()将为您填充,以使Foo foo[10];
之类的内容按照请求对齐foo[i]
。
因此,在我们的情况下,使用sizeof(T) == 48
,这意味着sizeof(cache_line_storage<T>) == 64
。
因此,对齐为您提供了您希望的填充。
但是,这是模板中的一个“错误”。考虑这种情况:
#define CACHE_LINE_SIZE 32
sizeof(T) == 32
我们最终得到char pad[1];
。这意味着sizeof(cache_line_storage<T>) == 64
。可能不是你想要的!
我认为模板需要稍微修改一下:
template <typename T, int padding>
struct pad_or_not
{
T data;
char pad[padding];
};
// specialize the 0 case
// As it is late, I am SURE I've got the specialization syntax wrong...
template <typename T, int>
struct pad_or_not<0>
{
T data;
};
template<typename T>
struct cache_line_storage {
[[ align(CACHE_LINE_SIZE) ]] pad_or_not<T, (sizeof(T) > CACHE_LINE_SIZE ? 0 : CACHE_LINE_SIZE - sizeof(T) ) > data;
};
或类似的东西。
答案 2 :(得分:0)
“你不能拥有大小为0的数组,因此需要1才能使其编译” - GNU C允许将数组标注为零。 另请参阅http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Zero-Length.html