缓存线对齐(需要澄清文章)

时间:2009-11-16 19:44:15

标签: c++ multithreading caching c++11 memory-alignment

我最近在我的应用程序中遇到了我认为是错误共享的问题,并且我已经查询了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个字节就足够了?

3 个答案:

答案 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