我有一段代码如下所示:
核心0:
memset64(buffer, 0xFFFFFFFFFFFFFFFFULL, 4096);
position.atomic_set(1);缓冲区是指向DDR中4KB缓冲区的指针。位置是一个原子整数变量。
请参阅https://elixir.bootlin.com/linux/v4.1/source/arch/arm64/include/asm/atomic.h
核心1:
while (1) {
if (position.atomic_read() == 1) {
break;
}
}
*buffer = "4KB data";有两个线程同时工作在两个核心上。
核心0将首先将缓冲区设置为memset,然后将原子变量position设置为1。
核心1将原子化读取无限循环中的变量position,如果position的值为1,则它会中断并向缓冲区写入某些内容。
我遇到了一个错误:程序完成后,position的值是1,但是缓冲区的内容是0 0xFF。
这似乎是一个可能的根本原因,在核心1看来,原子变量在memset之前被设置为1,因此核心1对缓冲区的修改被核心0的memset覆盖。
我正在用arm64 gcc 8.3和-O2优化一起编译代码。精灵将运行在一个2集群,8核心臂皮质-A53 CPU.
我想知道在aarch64中,在CPU上的memset64()之前执行atomic_set()是否有可能?或者,是否有可能是另一个CPU内核在看到memset之前就看到了原子值的变化?
我对系统编程很陌生,所以我对内存模型这样的概念不太熟悉。我将非常感激任何人都能给我一些建议。
发布于 2022-11-01 07:08:17
在当前线程(调用上面这两行代码的线程)中,后续读取buffer中的值或读取position将具有预期的行为。因此,如果您的程序是单线程,您可以停止现在。
但是,轮询position和观察new_pos的其他线程随后可能会从buffer读取,但看不到原始线程所写的期望值。它可以从缓冲区读取“旧”值。这有时被称为内存排序或缓存一致性问题。这是完全正常的--特别是在多核和多处理器系统中。在单核系统上很少有问题。
您需要引入一个内存屏障来强制同步。最简单的方法就是使用互斥对象来读取和写入这些值。
也就是说,在原来的线程中:
{
std::lock<std::mutex>(mut); // mut is a shared instance of std::mutex
memset64(buffer, 0xFFFFFFFFFFFFFFFFULL, 4096);
position.atomic_set(new_pos);
}然后,“读取”位置和缓冲区从另一个线程,采取锁的第一。
{
std::lock<std::mutex>(mut); // same instance of mut above
auto pos = position.atomic_get();
if (pos != last_pos)
{
last_pos = pos;
// read values of buffer while inside the lock
}
}使用互斥体的一个副作用是,它可能使原子原语的使用变得不必要。
https://stackoverflow.com/questions/74272208
复制相似问题