【发布时间】:2009-10-26 08:52:43
【问题描述】:
我为 Linux 编写了一个 C 实用程序,它每秒检查一次 /proc/net/dev 的内容。我使用 fopen("/proc/net/dev", "r") 打开文件,然后在完成后使用 fclose()。
由于我使用的是“伪”文件而不是真实文件,所以每次读取文件时打开/关闭文件是否重要,还是应该在应用程序启动时打开它并保持打开状态整个时间?该实用程序作为守护进程启动,因此可能会运行很长时间。
【问题讨论】:
我为 Linux 编写了一个 C 实用程序,它每秒检查一次 /proc/net/dev 的内容。我使用 fopen("/proc/net/dev", "r") 打开文件,然后在完成后使用 fclose()。
由于我使用的是“伪”文件而不是真实文件,所以每次读取文件时打开/关闭文件是否重要,还是应该在应用程序启动时打开它并保持打开状态整个时间?该实用程序作为守护进程启动,因此可能会运行很长时间。
【问题讨论】:
没关系,不。但是,缓存/缓冲可能存在问题,这意味着实际上最好(最安全)按照您的方式进行操作,并且每次都重新打开文件。由于您很少这样做,因此不这样做不会获得任何性能,因此我建议您保留当前的解决方案。
【讨论】:
你想要的是无缓冲的阅读。假设您不能只切换到 read() 调用,打开设备,然后将流设置为无缓冲模式。这还有一个额外的好处,即完成后无需关闭流。只需倒带,重新开始阅读。
FILE *f = fopen("/proc/net/dev", "r");
setvbuf(f, NULL, _IONBF, 0);
while (running)
{
rewind(f);
...do your reading...
}
【讨论】:
setvbuf() 是必需的。 /proc 中的文件可以通过 stdio 缓冲读取。无论如何,我必须检查rewind() 确实丢弃了以前读取的数据,我的系统就是这种情况。如果不确定,可以在rewind() 之后使用fflush()。
“/proc”中的伪文件对于守护进程来说是危险的,因为如果内核决定删除它们,它们就会消失,留下一个无效的FILE * 结构。这意味着您的策略是处理“/proc”中文件的唯一正确策略(但没有人会期望内核在运行时删除“/proc/net/dev”)。
一般情况下(尤其是“/proc/[PID]”中的文件)应该在操作前打开“/proc”中的文件,并在操作完成后尽快关闭它们。
请参阅此示例代码。它分叉并读取子进程的“/proc/[PID]/status”文件,一次在子进程退出之前,一次在子进程清理期间。
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char** argv){
pid_t child=fork();
if(child==0){
sleep(1);
} else {
char path[256],buffer[256]; int status,read_length;
sprintf(path,"/proc/%i/status",child);
//do a read while the child is alive
FILE *fd=fopen(path,"r");
if(fd!=0){
read_length=fread(buffer,1,255,fd);
printf("Read: %i\n",read_length);
fclose(fd);
}
//repeat it while the child is cleaned up
fd=fopen(path,"r");
wait(&status);
if(fd!=0){
read_length=fread(buffer,128,1,fd);
printf("Read: %i\n",read_length);
fclose(fd);
}
}
}
结果如下
f5:~/tmp # ./a.out
Read: 255
Read: 0
如您所见,如果“/proc”中的文件在您的程序运行时被内核删除,您很容易得到意外结果。
【讨论】:
fopen()的返回