在两个线程上读/写 64 位,无互斥/锁定/原子
Read/write 64-bits on two threads without mutex/lock/atomics
我有一个 64 位结构std::array
,其中每个结构如下所示:
MyStruct
{
float _a{0};
float _b{0};
}; // Assume packed
一个线程(CPU 内核(将写入 64 位对象,另一个线程(不同的内核(将读取它。
我使用的是英特尔 x86 架构,我知道 64 位写入保证是原子的,来自英特尔开发人员手册。
但是,我担心第二个线程可能会在寄存器中缓存该值,并且无法检测到该值何时更改。
- MESIF协议会保证第二个线程看到写入吗?
- 我是否需要
volatile
关键字来告诉编译器另一个线程可能正在修改内存? - 我需要原子学吗?
写入值的线程对性能非常敏感,如果可以的话,我想避免内存障碍、互斥锁等。
无论volatile
是否会在下一个C++版本中被弃用 -volatile
从未设计或打算用于多线程!这与Java形成鲜明对比,Java的易失性意味着完全不同的东西(Java易失性语义更接近于C++原子学的语义(。
最好有更多关于实际问题的信息,即,关于你实际想要实现的目标的更多背景。
根据您的描述,您只涉及两个线程 - 一个读取和一个写入 - 我建议使用单生产者-单消费者队列。这样的队列可以只用两个用于头/尾索引的原子计数器来实现;值本身不必是原子的,可以是任何类型的(包括不可复制的值(。
但是要了解这是否是一个有效的解决方案,我需要更多信息: 这些物品应该以先进先出还是后进先出消费?阵列呢?它有多大?它可以溢出/下溢(即线程尝试写入/读取条目,但数组已满/空(?应如何处理已满/空数组?
作为一个C++开发人员,你应该对 cpu 的低级功能持保留态度。请参阅这个有趣的问题:"理解标准::hardware_destructive_interference_size和标准::hardware_constructive_interference_size">
在缓存行之间真正共享appens,从我们可以看到的,上面的结构应该像这样修改:
struct MyStruct
{
alignas ( hardware_constructive_interference_size ) atomic < float > _a;
alignas ( hardware_constructive_interference_size ) atomic < float > _b;
};
并发访问变量总是需要使用 std::atomic。如果您的目标应用程序要按顺序执行写入对您来说并不重要C++。 很多事情都在引擎盖下进行,最后易失性不起作用,它已被std::atomic
超级种子并被弃用。
MESIF协议会保证第二个线程看到写入吗?
不,这取决于操作系统,如果你的第一个(写入线程(被优先考虑,并且在第二个线程甚至可以读取第一个线程之前设法写入两次,那么这就是数据竞争,完全依赖于操作系统。
我是否需要 volatile 关键字来告诉编译器另一个线程可能正在修改内存?
volatile
告诉编译器不要优化变量,根本不优化它。
我需要原子学吗?
取决于,您不打算使用互斥锁,您不打算使用任何与远程并发相关的内容,除了原子学,它更适用于跨线程编写。
我建议将 std::mutex 与std::lock_guard
或std::scoped_lock
结合使用。
我知道你的标题说你不想要它,但这确实是保证每次阅读和写作顺序相同的唯一方法。
- MESIF - 对寄存器没有影响。
- 易失性 - 在过去用于此,但在较新的编译器中,它仅用于从硬件寄存器读取以强制读取,因此它不起作用。
-
原子 - 一旦你有两个线程一起通信,你就需要原子操作来读取和写入。
std::atomic whatEver;
如果你幸运的话,你会得到
bool is_lock_free = whatEver.is_lock_free();
更幸运的是,如果
bool is_lock_free = whatEver.is_always_lock_free();
你将不得不做
auto whatEver = arrayOfWhatEver[x]; // atomic
auto a = whatEver._a;
使用原子操作,而不仅仅是读取 MyStruct 的各个成员。
- std::原子加载和存储都需要吗
- 如何找到锁定Linux futex的C++行
- G锁定铸造到基础上会释放模拟行为
- 松弛原子与无同步情况下的记忆连贯性
- 如何检查线程是否锁定
- 如何在C++中找到active directory中禁用和锁定的窗口帐户
- 我应该在锁定TBitmap画布后解锁它吗
- 在一个读写器队列中,我可以用volatile替换原子吗
- 如何使用原子指针执行双缓冲
- C++中原子的替代品<variant>
- 原子读取是否保证读取最新值
- 在两个线程上读/写 64 位,无互斥/锁定/原子
- 在以读取为主的多线程程序中,可以使用原子来减少锁定吗
- 用原子索引从静音阵列中锁定互斥品
- 结构专业的原子类型如何免费锁定
- 如何使推送和弹出队列成为原子,如何锁定这些操作
- SPSC锁定免费队列,无原子
- 使用原子锁定自由的单生产者多消费者数据结构
- c++中原子的乐观锁定策略和排序
- 我们可以在不锁定两个或更多无锁容器的情况下原子地做一些事情吗?