【问题标题】:mmap shared buffer read problemsmmap 共享缓冲区读取问题
【发布时间】:2012-02-07 23:43:09
【问题描述】:

我有一个内核模块,它分配了一个大的内存缓冲区,然后这个缓冲区被映射到用户空间。
模块从硬件接收一些数据,然后将新数据放入缓冲区,缓冲区前面有一个标志。 (内存初始化为零,标志为1)。

用户空间程序在返回指向有效数据的指针之前循环读取标志

简化版代码:

uint8_t * getData()
{
    while(1)
   {
      if(*((volatile uint32_t*)this->buffer) == 1)
          return this->buffer+sizeof(uint32_t);
   }
}

内存区域被映射为共享,并且完整的缓冲区内存转储确认缓冲区已正确写入。

问题是在正确读取一定次数后,此函数停止返回。
这可能是由于 CPU 缓存造成的吗?有没有办法避免这种情况并确保每次都直接从 RAM 读取而不是从缓存中读取?

【问题讨论】:

  • 这是非常特定于架构的,您还没有告诉我们您的架构。从广义上讲,如果这确实是问题所在,那么在写入内核之后发出存储/释放屏障,以及在读取用户空间之前发出加载/获取屏障就足够了。
  • @Lifesworder 看起来您是新用户,但这里的礼仪要求您在提出问题并得到一些答案时做出回应。
  • 我很抱歉,截止日期,还有很多事情要做:)。我不确定是什么首先导致了问题,但似乎从内核空间 mmap 处理程序中删除标志 MAP_SHARED 和 MAP_LOCKED 解决了问题......
  • 我的意思是来自 vma->flags 的 VM_LOCKED 和 VM_SHARED。

标签: c++ c linux mmap cpu-cache


【解决方案1】:

是的,这可能是由于读取器端的 cpu 缓存所致。有人可能认为“volatile”关键字应该可以防止此类问题,但这并不完全正确,因为 volatile 只是对编译器的一个指令,不要注册变量,与指示 cpu 直接从主存储器读取并不完全相同每次。

问题需要在写端解决。根据您的描述,听起来写入发生在内核模块中并从用户端读取。如果这两个操作发生在不同的 cpus(不同的缓存域)上,并且没有任何东西可以触发读取端的缓存失效,那么正如您所描述的那样,您将卡在读取端。您需要在存储指令之后强制在 linux 内核上刷新存储缓冲区。假设它是 linux 内核,在您设置标志后立即插入对 smp_mb 的调用,并且模块中的值很可能在所有架构上都做正确的事情。

【讨论】:

  • 由于我一直在单核上进行测试,这对我的问题本身没有帮助,但是当我必须将其移植到多核处理器上时,你的答案会派上用场(我会的)。
  • 啊……有趣。不知何故,现在很容易假设每个人都在开发多核系统。
【解决方案2】:

提醒用户空间应用程序存在更多数据的更好方法是将其阻塞在内核模块提供的文件描述符上的read() 中,当更多数据可用时内核模块将其唤醒。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-18
    • 2018-06-08
    • 1970-01-01
    • 1970-01-01
    • 2013-11-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多