【发布时间】:2019-02-13 16:23:11
【问题描述】:
我有一个在 Intel Xeon 32 内核上运行的 C++ 多线程应用程序,使用 GCC 4.8.2 编译并启用了优化。
我有多个线程(例如 A、B、C)更新某些 POD 类型,另一个线程 D 每 K 秒读取这些变量并将其发送到 GUI。线程跨多个内核和套接字生成。写入受自旋锁保护。线程 A、B、C 对延迟敏感,高性能是一个关键方面。线程 D 对延迟不敏感。
类似:
Thread A,B,C
...
// a,b,c are up to 64 bits (let's say double)
spin-lock
a = computeValue();
b = computeValue();
c = computeValue();
spin-unlock
....
Thread D
...
// a,b,c are up to 64 bits (let's say double)
currValueA = a;
currValueB = b;
currValueC = c;
sendToGui(currValueA ,currValueB ,currValueC );
....
我想利用关于保证原子操作的第 8.1.1 段https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.html,并避免使用锁来保护线程 D 进行的读取。
我的理解是,如果 a、b、c 是自然对齐的(大小不超过 64 位),线程 D 没有风险可以读取在写入过程中中途获取的 a、b、c 值.换句话说,写入和读取将自动执行。线程 D 将读取旧值或新值。
我的理解正确吗?
我留给编译器 GCC 4.8.2 来处理对齐,即我不使用任何 gcc 内置指令或函数,如 std::alignas、sts::alignof 等。
我知道代码不可移植。 我宁愿不使用 std::atomic 以避免任何不必要的开销。
【问题讨论】:
-
与
std::atomic并指定目标架构,编译器可能会自己进行优化。所以你的代码将是可移植的。让编译器工作给编译器。 -
你有没有发现使用
std::atomic造成的任何“不必要的开销”? -
将
std::atomic与memory_order_relaxed一起使用对于纯加载和纯存储根本不会产生任何开销(并且即使在32 位代码中也能确保64 位值的正确对齐,其中@ 987654327@ 在 Linux 上),但它会干扰自动矢量化。 (当然,避免使用任何原子 RMW 操作)。如果您关心性能,请考虑使用更新的编译器,例如 gcc7 或 gcc8。自 4.8 以来进行了各种改进。 -
感谢您的 cmets。我比较了使用原子存储(memory_relaxed 和 target 指定)和正常分配生成的程序集。他们看起来有点不同。我看到另外两条指令:movabsq 和 movq。我不能说它们是否对性能有任何影响。我也绝对应该尝试更新的 g++。谢谢。
-
如果你想使用 Intel 规范进行“全金属”编程,你会使用内联汇编吗?
标签: c++ multithreading x86 atomic memory-alignment