我有一个内核模块分配了一个大的内存缓冲区,然后这个缓冲区被映射到用户空间。
该模块从硬件接收一些数据,然后将新数据放入缓冲区,并在其前面加上一个标志。 (内存初始化为0,flag为1)。
用户空间程序在返回指向有效数据的指针之前循环读取标志
代码的简化版本:
uint8_t * getData()
{
while(1)
{
if(*((volatile uint32_t*)this->buffer) == 1)
return this->buffer+sizeof(uint32_t);
}
}
内存区域被映射为共享,并且完整的缓冲区内存转储确认缓冲区被正确写入。
问题是在一定数量的正确读取之后,这个函数停止返回。
这可能是由于 CPU 缓存造成的吗?有没有一种方法可以避免这种情况并确保每次都直接从 RAM 而不是从缓存中进行读取?
最佳答案
是的,这可能是由于读取器端的 CPU 缓存所致。有人可能认为“volatile”关键字应该可以防止此类问题,但这种说法并不完全正确,因为 volatile 只是指示编译器不要注册变量,与指示 cpu 直接从主内存读取不完全相同每次。
问题需要在写端解决。根据您的描述,这听起来像是写入发生在内核模块中并从用户端读取。如果这两个操作发生在不同的 cpu(不同的缓存域)上,并且没有任何东西可以在读取端触发缓存失效,那么您将像您描述的那样卡在读取端。您需要在存储指令后强制在 linux 内核上刷新存储缓冲区。假设它是 linux 内核,在设置标志和模块中的值后立即插入对 smp_mb 的调用很可能在所有架构上都做正确的事情。
关于c++ - mmap共享缓冲区读取问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9185803/