正确读取 /proc/pid/status 的方式

Correct way of reading /proc/pid/status

提问人:lstipakov 提问时间:8/11/2016 更新时间:11/20/2017 访问量:5197

问:

我是这样读的:/proc/<pid>/status

std::ifstream file(filename);
std::string line;
int numberOfLinesToRead = 4;
int linesRead = 0;

while (std::getline(file, line)) {
    // do stuff
    if (numberOfLinesToRead == ++linesRead) {
        break;
    }
}

我注意到在极少数情况下会挂起。std::getline

  1. 为什么会这样?我的印象是 proc 文件系统应该处于某种一致的状态,并且不应该出现缺少换行符的情况。我的假设是,当发生 EOF/错误时返回。getlinefalse
  2. 推荐的、安全的阅读方式是什么?/proc/<pid>/status
C++ Linux 字符串 std procfs

评论

1赞 Some programmer dude 8/11/2016
这是逐行准备任何文本文件的“正确”方法。但是,如果正在检查的进程在读取文件时退出,则与读取其他文本文件相比,行为可能有所不同。没有 std::getline 不返回布尔值,它返回可以在布尔表达式中使用的流。
0赞 Some programmer dude 8/11/2016
至于你的第二个问题,实际上没有安全的方法来读取任何文件,因为另一个进程可能随时退出。您可能需要使用其他一些特定于 Linux 的系统调用来获取进程的状态,最好是在内核写入结构的直接系统调用中,而不是使用标准 C++ 库从文件中读取。/proc/<some pid other than your own>/
2赞 Galik 8/11/2016
我很惊讶这应该挂起来。我怀疑这可能是编译器中的错误,也许是因为如果另一个进程从您下面删除一个文件,那么它应该在您的文件描述符中干净地生成错误。并且应该像任何其他文件一样运行。你确定那个确切的代码导致了他的错误吗?OS/proc
0赞 lstipakov 8/11/2016
@Galik是的,很确定。由 gdb 附加,检查回溯,继续执行,再次检查回溯。这是它: gist.github.com/lstipakov/95e6091d53e8f779c14800e6309109c0
0赞 osgx 3/11/2017
@lstipakov,程序挂起时的输出是什么?strace

答:

0赞 Matthew Fisher 8/11/2016 #1

也许更确定的路径是将 fread 使用到一个大缓冲区中。状态文件很小,因此请分配一个本地缓冲区并读取整个文件。

示例:查看最简单解决方案的第二个答案

这可能仍然在 fopen 或 fread 上失败,但应该返回一个合理的错误。

-2赞 Alexey Kamenskiy 8/13/2016 #2

/proc 是一个虚拟文件系统。这意味着从其中的“文件”读取与从普通文件系统读取不同。

如果进程退出,则从 /proc 中删除有关它的信息比实际文件系统快得多(这里涉及脏缓存刷新延迟)。

请记住这一点,想象一下,在您阅读尚未缓冲的下一行之前,该进程会退出。

解决方案是考虑文件丢失,因为您可能不需要有关不再存在的进程的信息,或者缓冲整个文件,然后只解析它。

编辑:挂起进程显然应该与这是虚拟文件系统这一事实有关。它的行为方式与实际文件系统不完全相同。由于这是特定的 fs 类型,因此问题可能出在 fs 驱动程序中。您提供的代码对于正常文件读取来说看起来不错。

评论

0赞 osgx 3/11/2017
亚历克斯,在问题的示例中,进行了哪些系统调用以从 proc 读取文件?那里有多个系统调用吗?对整个文件(全有或全无)进行一次性足够大的读取,然后从用户缓冲区进行解析会更安全。