c++ - 线程安全,无锁增量函数?

标签 c++ c linux multithreading lock-free

已更新:是否有线程安全、无锁且适用于所有 Linux 发行版的 C 或 C++ 函数 increment

最佳答案

2021 年答案

C++

自其他答案以来已经过去了 12 年,现在它已成为标准,并且自 C++11 以来使用 atomic operations library 就可以做到这一点.

#include <iostream>
#include <atomic>

int main() {
    std::atomic<int> atomic_i{5};
    std::cout << atomic_i.is_lock_free() << std::endl; // 1, which means lock free
    atomic_i++;
    std::cout << atomic_i << std::endl; // 6
    return 0;
}

如果有兴趣,可以编译成(至少对 gcc 进行 -O1 优化):

mov             DWORD PTR [rsp-4], 5
lock inc        DWORD PTR [rsp-4]

如果你想要一个普通的、非原子的整数,你只想在某些时候在原子操作中递增,你可以使用 atomic_ref 自 C++20 起,如果您确保它充分对齐。 (一些系统由于历史 ABI 原因而使一些非原子类型对齐不足,但需要自然对齐才能使原子实际有效/正确地工作。值得注意的是 32 位 x86,带有 int64_tdouble,其中 alignof(T) < std::atomic_ref<T>::required_alignment)。

请注意“虽然存在引用对象的任何 atomic_ref 实例,但必须通过这些 atomic_ref 实例独占访问该对象。”
参见 on Godbolt它是如何编译的。

// This alignment is redundant for int on most mainstream implementations
// but is important for portability or for wider types like int64_t
alignas(std::atomic_ref<int>::required_alignment)  int j = 8;

... // pass the address of j to other threads
{
    std::atomic_ref<int> refj(j);
    refj++; // atomic operation, j is now 9
}
// refj goes out of scope, so it's ok to use j again

 ... // some synchronization so we know other threads are done for now
j++; // non-atomic increment, j is now 10

C

您也可以使用 atomic types 在 C11 中执行与我的第一个示例相同的操作.

#include <stdatomic.h>
#include <stdio.h>

int main() {
    atomic_int i = 5;
    i++; // atomic operation
    printf("%d\n", i); // 6
    return 0;
}

没有 C++20 的 C 等价物 std::atomic_ref .如果您不介意使用 GNU 扩展,您可以使用 C++ atomic 的内置函数。和 atomic_ref在之上实现,例如 GNU C __atomic builtins : __atomic_fetch_add( &i, 1, __ATOMIC_ACQ_REL) .

非 Linux 系统的其他编译器有自己的内置函数,例如 MSVC_InterlockedAdd .

指向 atomic_int * 可能会起作用(又名 _Atomic int* )在 int 的地址,但这是严格别名的未定义行为。

关于c++ - 线程安全,无锁增量函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1694963/

相关文章:

c++ - 为什么 std::list 想不带参数调用我的分配器?

c - 为 C 代码生成调用图

linux - 为什么 cp 无法复制/proc/stat 文件?

c - 消息队列示例中的 realloc 或 free 错误

c++ - 什么是 C++ 数组中的初始化程序?

c++ - 能否获取成员函数模板参数的所属对象?

c++ - 将此实例变量添加到 C++11 文件的 header 会使编译器陷入困境。为什么?

c - BYTE BCD 到 ASCII 转换优化

c - 如何使用 libcurl 登录安全网站并获取登录后的 html

linux - 取消设置 C-Shell 中的所有环境变量