已更新:是否有线程安全、无锁且适用于所有 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_t
和 double
,其中 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/