我正在创建一个非常快速的多线程离散事件模拟框架。该框架的核心使用原子和无锁编程技术来实现跨多个线程的非常快速的执行。这要求我将一些变量与缓存行对齐并填充剩余的缓存行空间,以便我不会有缓存行争用。这是我的做法:
// compute cache line padding size
constexpr u64 CLPAD(u64 _objSize) {
return ((_objSize / CACHELINE_SIZE) * CACHELINE_SIZE) +
(((_objSize % CACHELINE_SIZE) > 0) * CACHELINE_SIZE) -
_objSize;
}
alignas(CACHELINE_SIZE) MyObject myObj;
char padding[CLPAD(sizeof(myObj))];
这对我来说非常有用,但是当我今天将此方法用于新对象类型时,我偶然发现了一个问题。CLPAD() 函数返回将输入类型填充到下一个缓存行所需的字符数。但是,如果我输入的类型大小正好是缓存行数的倍数,则 CLPAD 返回 0。如果尝试创建大小为零的数组,则会收到以下警告/错误:
ISO C++ forbids zero-size array 'padding'
我知道在这种情况下我可以修改 CLPAD() 以返回CACHELINE_SIZE,但随后我无缘无故地烧毁了一行缓存空间。
如果 CLPAD 返回 0,如何使"填充"声明消失?
从std::aligned_storage<>
中获取一页,我想出了以下内容:
template<class T, bool = false>
struct padded
{
using type = struct
{
alignas(CACHELINE_SIZE)T myObj;
char padding[CLPAD(sizeof(T))];
};
};
template<class T>
struct padded<T, true>
{
using type = struct
{
alignas(CACHELINE_SIZE)T myObj;
};
};
template<class T>
using padded_t = typename padded<T, (sizeof(T) % CACHELINE_SIZE == 0)>::type;
用法:
struct alignas(32) my_type_1 { char c[32]; }; // char c[32] to silence MSVC warning
struct my_type_2 { char c[CACHELINE_SIZE * 2]; }; // ditto
int main()
{
padded_t<my_type_1> pt0;
padded_t<my_type_2> pt1;
sizeof(pt0); // 128
alignof(pt0); // 128
sizeof(pt1); // 256
alignof(pt1); // 128
}
您可以根据需要提供访问myObj
的功能。