c++ - DMA 的同步要求

标签 c++ c++11 synchronization embedded

我给你讲个故事:

我有两个缓冲区设置,用于执行所谓的 ping ponging。我有一个指向每个缓冲区的 DMA 系统。

系统设置为 DMA 将数据写入一个缓冲区,而中断处理另一个缓冲区中的数据。

看起来像这样:

#include <atomic>
#include <array>
#include <algorithm>

using buf_t = std::array<std::uint32_t, 32>;

std::array<buf_t,2> ping_pong;

/*
 * In this example I am just going to push the data to a "peripheral"
 */
#define PORT (*(volatile std::uint32_t*)0x1234)


void handle_data(buf_t const& data)
{
    std::for_each(std::begin(data),std::end(data), [](auto x){
        PORT = x;
    });
}

void isr1(void)
{
    std::atomic_thread_fence(std::memory_order::memory_order_acquire);
    handle_data(ping_pong[0]);
}
void isr2(void)
{
    std::atomic_thread_fence(std::memory_order::memory_order_acquire);
    handle_data(ping_pong[1]);
}

现在我的问题是:

这是定义的行为吗? 是什么阻止了编译器摆脱对 ping_pong 的任何访问,因为它看不到设置它的内容?

至少对于当前的 gcc 编译器,它似乎 可以工作:godbolt

最佳答案

我手头没有任何硬性答案,但乍一看,我会假设因为 ping_pong 是全局的,它有外部链接,因此编译器无法在那个翻译单元中优化它。

编译器不知道它将从那个 TU 中的什么地方写入,但是,当最终将所有 TU 链接在一起(对于应用程序)时,我会假设如果仍然不使用该对象可能会被丢弃。如果这段代码被编译成一个库,编译器将保持这个全局对象不变,因为它不知道外部代码是否会使用它。

==

我破解了你的代码以在 main 中创建 ping_pong,并调用:isrX(ping_pong[y]),它在 clang 上,导致包括 ping_pong 在内的大部分代码在 clang 上被优化掉。这似乎表明外部链接正在保持 ping_pong,而不是端口是易变的/从源自 ping_pong 数组的数据写入端口。

正如您所注意到的,在 GCC 上,代码保持完整,这可能暗示这是未定义的行为。存在另一种可能性,对于 GCC,编译器可能会检测到修改任何导致更新 volatile 端口的源变量将不会剔除这些源变量。

关于c++ - DMA 的同步要求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63090625/

相关文章:

c++ - 为什么我的二维数组不旋转?

c++ - 为什么排在 char 队列的前面会导致 bad_alloc?

c++ - 即使使用 -fno-elide-constructors 进行编译,似乎也会发生复制省略

c# - 如何确保 MonoBehaviour 对象在另一个 Actor 想要访问它之前加载了它的数据?

mysql - 跨应用程序环境的 Amazon RDS 数据库

core-data - 核心数据和 cloudkit 同步 wwdc 2019 不适用于 beta 3

c++ - Hook 和取消 Hook 一个文件 DLL

c++ - 在执行时加载常量,一次还是两次?

c++ - 为什么 std::is_move_constructible<S>::value == false 尽管 S move 构造很好?什么是正确的行为?

c++ - C++中Boost.Geometry中的多边形转换:直线的平移,旋转,反射