Skip to content

败犬日报 2025-01-03

1. 多线程写相邻变量

cpp
struct Point {
    int x;
    int y;
};

int main() {
    struct Point point = {0, 0};

    // Thread 1
    for (int i = 0; i < 100; i++) {
        point.x++;
    }

    // Thread 2
    for (int j = 0; j < 100; j++) {
        point.y++;
    }
}

缓存一致性保证了最终结果不会出现 point.xpoint.y 不一致的情况。

所以问题只出在性能上,即伪共享(false sharing)。伪共享是多个线程同时修改位于同一 cacheline 中的不同变量,cacheline 会频繁地在多个核的 cahe 之间切换,从而降低性能。

解决方案是通过对齐让 x, y 位于不同的 cacheline 里(cacheline 是 64 字节,考虑到相邻 cacheliine 的硬件预取,推荐 128 字节对齐):

cpp
struct Point {
    alignas(128) int x;
    alignas(128) int y;
};

此事在 c++ 性能优化指南上亦有记载。

2. C++ 和 Java 的 volatile 有啥共同点

名字一样,没了。

C++ 的 volatile 极少使用,它的语义和 Java 的 volatile 完全不同。Java 可以用来做线程同步,C++ 请使用 std::atomic

3. 转换函数(operator T())必须用别名

cpp
struct A {
    using T = int (*)(int);
    operator T() {
        return nullptr;
    }
};

https://zh.cppreference.com/w/cpp/language/cast_operator 记载:

转换类型标识是一个类型标识,但它的声明符中不能出现函数与数组运算符 []()(因此转换到例如数组的指针的类型就需要使用类型别名、typedef 或标识模板:见下文)

普通的成员函数不需要别名。