在虚拟机上运行的 C++ 多线程文件读取问题

Posted

技术标签:

【中文标题】在虚拟机上运行的 C++ 多线程文件读取问题【英文标题】:Issue with C++ Multithreaded file read running on virtual machines 【发布时间】:2016-08-29 19:02:22 【问题描述】:

这更像是一个概念性问题。我正在使用的遗留代码有一个 C++ 线程实现来模拟并行文件读取。它处理多线程文件读取的方式是仅将文件中的一个数据块(比如说2^20 bytes)流式传输到char* array,然后多个线程读取该数组的专用部分。当一个线程完成时,它等待所有其他线程完成(即,使用unique_lock 上共享的condition_variable)和最后一个线程完成,将下一个数据块从文件加载到数组中并继续该过程直到整个文件被读取。并行读取的原因是这些文件通常超过1 GB,否则非常耗时。这样做的速度大约是6x 或更多。

我观察到一些奇怪的行为。当代码在物理机上运行时(即使它是远程连接的),多线程文件读取始终正常工作。但是,如果它在虚拟机上运行,​​有时它会在读取后丢失数据。我已经调试了每个线程只读取一行,但有时结果仍然不正确。这表明不正确结果的原因不是读取错误,而是输入文件中缺少整行(.txt)。如果我增加线程数(线程数越高,失败的频率越高)并增加文件大小(即,如果文件大小大于char* array 的大小),我可以更频繁地重现错误结果。这使我相信问题不在于多线程文件读取,而与运行时环境(物理机与虚拟机)有关。

我只是在大声思考,想看看是否有人经历过类似的行为,或者是否有任何关于为什么会发生这种行为的见解。我正在调查任何buffer overflow 问题,但到目前为止没有发现任何问题。

编辑: 添加有关环境的更多信息

我正在使用Visual Studios 2013,所以使用MS Visual C++编译器,所有物理机和虚拟机都是Windows Server 2012 R2Windows Server 2008 R264-bitx64-based processors最小可用内存是32GB并且可以去到120GB。服务器使用不同版本的Intel Xeon E5 CPU。

【问题讨论】:

你能重现一点sn-p代码吗?此外,更多的上下文应该有助于回答。物理机是什么平台?虚拟的呢?你如何编译它?尝试描述两种环境之间的更多差异 @BiagioFesta 感谢您的评论。添加了更多细节,但遗留代码与许多其他函数相互依赖,并且难以重现准确的 sn-p。 【参考方案1】:

这几乎可以肯定意味着您的代码存在竞争条件,这种情况通常很少发生,但会被您的 VM 上的条件所引发。

也许由于间歇性可用内核或不同的时间切片导致不同的线程调度,甚至从相对自愿的任务切换到更抢先的任务切换,都在强调这个问题。您也可能在某处遗漏了错误检查,也许行读取功能有时会读取部分行,因为您不检查但很少发生在真铁上的可恢复 IO 错误。但是由于您没有发布代码,我无法开始调试它。

TLDR 几乎可以肯定您的代码有问题,而不是 VM 实现(假设它是主流虚拟机管理程序)。

顺便说一句,尽管这与您的问题无关,但我不明白为什么您可能会以这种方式执行此文件 IO,而不是对文件进行映射并让线程从 mmap 中读取。在大多数情况下,这将大大提高效率,并且在大多数操作系统上本质上是线程安全的。

【讨论】:

感谢@Vality 提供一些见解。我也在考虑做一个内存映射实现。代码至少有几年的历史,不知道当前设计背后的确切决定。 @kishansudu 不用担心,我很高兴这个答案至少有点帮助,有时我们都必须维护旧代码,所以祝你好运找到问题。

以上是关于在虚拟机上运行的 C++ 多线程文件读取问题的主要内容,如果未能解决你的问题,请参考以下文章

C++ 多线程 同时读取同一个vector 线程安全 吗

C++ 多线程 同时读取同一个vector 线程安全 吗

C++ - 可执行文件的传输

在 C++ 中,如何使用多个线程读取一个文件?

java内存映射文件多线程读/写

java多线程批量读取文件