【问题标题】:How do the sync() call and the sync command differ?sync() 调用和 sync 命令有何不同?
【发布时间】:2014-01-14 06:51:04
【问题描述】:

我使用 mmap() 和 fopen("/dev/mem") 来创建一个映射到 ARM 系统中两个处理器内核之间共享的物理内存块。当运行 Linux 的处理器写入内存时,在其他非 Linux 处理器看到写入的数据之前可能会有超过一秒的延迟。如果 Linux 进程在写入内存后立即进行此系统调用,那么长时间的延迟就会消失:

system("sync; echo 3 > /proc/sys/vm/drop_caches" );

我尝试直接在代码中复制该逻辑,但长时间的延迟仍然存在:

int fd;
char* data = "3";
sync();
fd = open("/proc/sys/vm/drop_caches", O_WRONLY);
write(fd, data, sizeof(char));
close(fd);

为什么 sync() 调用与同步系统命令的行为不同?同步命令是否会影响同步()调用不影响的虚拟内存刷新?

我知道手册说同步程序除了执行 sync(2) 系统调用之外什么都不做,但是我从用户空间调用 sync() 的事实会影响它的行为吗?它的作用就像从用户空间调用同步只是安排同步而不是阻塞直到完成。

【问题讨论】:

  • 这感觉有点远,但是您的echo 将2 个字节(3\n)写入drop_caches,而您的其他代码只写入3。会不会有区别?
  • @WumpusQ.Wumbley sizeof(char) == 1
  • 我尝试了这两种方法,没有尾随换行符,但没有区别。在我的示例中编码的系统回显命令会输出(隐含的)换行符。

标签: c linux sync mmap


【解决方案1】:

你忘记换行了。

echo 3 输出"3\n"

此外,您正在采取一种非常迂回的方式来实现共享内存,并且这样做会给操作系统的其余部分带来巨大的成本。

每次调用 sync-the-command 或 sync-the-system-call 时,都会导致操作系统刷新整个计算机上的每个文件系统;更糟糕的是,您告诉操作系统忘记它拥有的每个文件系统缓冲区,从而迫使操作系统从磁盘重新读取所有内容。几乎所有你能想到的方式都对整个操作系统的性能造成了恶劣的影响。

有一个更简单的方法。

使用 shm_open() 创建一个命名的共享内存区域。使用 mmap 访问它。 仅在该内存块上使用内存屏障或共享/命名互斥体,以确保您可以一致且安全地对其进行读写。

就复杂性而言,您当前的方法可能比普通共享内存的成本高出 1,000,000 倍。

【讨论】:

  • 我有一个单独的问题悬而未决,专门解决如何刷新使用 mmap 映射的内存。请参阅此link。当前的问题更多是关于尝试理解为什么两种假定相同的同步方法表现不同。
  • shm_open 建议似乎不是在这种情况下可行的解决方案,因为第二个处理器没有运行 Linux。我错了吗?
  • 说什么?您有两个可以访问相同内存的处理器,但运行的是两个不同的操作系统?你有什么样的系统架构?您是在说 DSP 之类的子处理器吗?
  • 这是一个非对称多处理系统 (AMP)。一个处理器正在运行 Linux,用于 UI 和一般应用程序开发。另一个处理器运行实时算法,作为支持 FPGA 的数据采集系统的一部分。整个系统(两个 ARM 内核、共享内存控制器和一个 FPGA)都在一个 Xilinx Zynq 芯片中。
  • 啊。这类信息会在前期非常很有帮助:)。所有这些关于“共享内存”的讨论都是错误的。您只想让 linux 处理器写入某个物理地址并确保处理器完成该写入。这不需要涉及同步或删除 VM 缓冲区等。
【解决方案2】:

drop_cachessync 在这里都不合适,因为它们都处理文件系统缓存——这实际上并不是您在这里遇到的。 sync 似乎解决了它的事实可能是巧合。 (可能是在启动sync 工具时顺便刷新了数据缓存。)

您的应用程序很可能在系统上的两个处理器内核之间遇到缓存同步问题。尝试使用cacheflush() 系统调用来解决这个问题:

#include <unistd.h>
#include <asm/unistd.h>
...
syscall(__ARM_NR_cacheflush, mapping_ptr, mapping_ptr + mapping_length, 0);

请注意,您可能需要在两个进程中刷新缓存才能看到正确的结果。

其他映射设备通常需要刷新对映射内存的更改,但我认为在这种情况下可能不需要。不过,尝试msync() 也无妨:

msync(mapping_ptr, mapping_length, MS_SYNC); // on process writing to memory
msync(mapping_ptr, mapping_length, MS_INVALIDATE); // on process reading from memory

最后,确保您使用MAP_SHARED 标志映射此内存。

【讨论】:

  • 根据手册,cacheflush 系统调用仅在基于 MIPS 的系统上可用。我有一个 ARM 系统,没有 asm/cachectl.h 源文件,因此代码 sn-p 无法编译。我还尝试了 msync()、fsync() 和 fdatasync(),但这些都不会影响延迟。作为记录,我确实在内存映射上使用了 MAP_SHARED。我还尝试将 O_DIRECT 添加到关联的打开调用中,但我的内核在该标志上抛出了无效参数错误。
  • 手册页有点误导 - cacheflush() 也存在于 ARM 上,但有不同的参数列表,并且当前没有被 libc 包装。我已经更新了示例代码。
  • 对于它的价值,它也可以将硬件内存范围标记为不可缓存。不过,这需要比我熟悉的更多的魔法。
猜你喜欢
  • 2021-12-15
  • 2020-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多