描述了一个模板类或结构体的设计目的,这个设计旨在存储一个类型 T
,并添加足够的填充(padding),以确保该类型在 Folly 库所使用的范围内不会受到伪共享(false sharing)的影响。
伪共享(false sharing)是并行编程中常见的性能问题,发生在两个或多个线程访问位于同一缓存行(cache line)内的不同数据项时,即使这些线程只修改它们自己的数据,也会导致缓存行失效和不必要的缓存-主存传输。为了避免这种情况,可以通过添加填充来确保每个线程访问的数据项位于不同的缓存行中。
注释中的关键信息如下:
- 类型
T
:这是被存储的数据类型。 - 填充(padding):额外的内存空间,用于确保类型
T
的实例不会与其他数据项共享同一缓存行。 sizeof(T) <= alignof(T)
:这是一个条件判断,用于检查类型T
的大小是否小于或等于其对齐方式。如果满足这个条件,那么类型T
的一个实例将完全位于一个缓存行内,因此不会受到伪共享的影响(至少在这个条件下是如此)。然而,这个条件并不总是成立,特别是对于大型类型或具有特定对齐要求的类型。- Folly 库:Facebook 开源的 C++ 库,提供了许多用于高性能服务器应用的数据结构和工具。在这个上下文中,Folly 可能定义了它认为合理的缓存行大小,并提供了机制来避免伪共享
代码为:
template <typename T>
class CachelinePadded {
static_assert(
alignof(T) <= max_align_v,
"CachelinePadded does not support over-aligned types.");
public:
template <typename... Args>
explicit CachelinePadded(Args&&... args)
: inner_(std::forward<Args>(args)...) {}
T* get() {
return &inner_;
}
const T* get() const {
return &inner_;
}
T* operator->() {
return get();
}
const T* operator->() const {
return get();
}
T& operator*() {
return *get();
}
const T& operator*() const {
return *get();
}
private:
static constexpr size_t paddingSize() noexcept {
return hardware_destructive_interference_size -
(alignof(T) % hardware_destructive_interference_size);
}
char paddingPre_[paddingSize()];
T inner_;
char paddingPost_[paddingSize()];
};
其中
constexpr std::size_t hardware_destructive_interference_size =
kIsArchArm ? 64 : 128;
使用实例:
struct RvalueOverloadedConstructor {
RvalueOverloadedConstructor(int* dst, int& /* ignored */) {
*dst = 0;
}
RvalueOverloadedConstructor(int* dst, int&& /* ignored */) {
*dst = 1;
}
};
int shouldBeZero = 12345;
int shouldBeOne = 67890;
{
int ignored = 42;
CachelinePadded<RvalueOverloadedConstructor> padded1(
&shouldBeZero, ignored);
CachelinePadded<RvalueOverloadedConstructor> padded2(
&shouldBeOne, static_cast<int&&>(ignored));
}
EXPECT_EQ(0, shouldBeZero);
EXPECT_EQ(1, shouldBeOne);