C语言中同一文件描述符能否同时读写及异常问题排查
问题根源
- 父子进程共享文件偏移量:
fork()生成的子进程会继承父进程的文件描述符,且两个进程的fd指向同一个系统文件表项,偏移量是共享的。父进程第一次写入5字节("abcd"+\0)后,文件偏移量会移动到第5字节位置,后续子进程调用read()时直接从偏移量5的位置开始读,此时文件末尾就是5,read()直接返回0(EOF),没有读取到任何有效数据,str指向的缓冲区保留的是栈上的原始垃圾值,自然输出乱码。 readLine函数缺少错误处理:当read()返回0(EOF)或-1(读取错误)时,不会修改传入的缓冲区内容,代码没有判断该情况就继续执行循环,要么读取垃圾值,要么进入死循环。- 子进程无等待逻辑:当没有新内容可读时,子进程会持续空转调用
read(),占用大量CPU资源。
修复方案
你可以选择以下任意一种方案解决偏移量共享问题,同时补充错误处理即可。
方案1:父子进程独立打开文件(推荐)
两个进程分别打开sharedFile,各自维护独立的偏移量,互不干扰,修改后代码如下:
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> void readLine (int fd, char *str) { int n; do { n = read(fd, str, 1); // 遇到EOF或错误直接返回,避免读垃圾值 if (n <= 0) { *str = '\0'; return; } } while (*str++ != '\0'); } int main(int argc,char ** argv){ int fd=open("sharedFile",O_CREAT|O_RDWR|O_TRUNC,0600); if(fork()==0){ // 子进程独立打开文件,使用独立偏移量 int read_fd = open("sharedFile", O_RDONLY, 0600); char buf[1000]; while(1) { readLine(read_fd, buf); // 读到有效内容再输出 if (buf[0] != '\0') { printf("%s\n",buf); } // 避免空转占CPU usleep(100000); // 100毫秒轮询一次 } }else{ while(1){ sleep(1); write(fd,"abcd",strlen("abcd")+1); } } }
方案2:共享fd,手动调整偏移量
如果要共用同一个fd,每次读写前手动设置偏移量即可,这里我们让父进程每次写在文件开头,子进程每次从开头读,还能避免文件无限膨胀:
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> void readLine (int fd, char *str) { int n; do { n = read(fd, str, 1); if (n <= 0) { *str = '\0'; return; } } while (*str++ != '\0'); } int main(int argc,char ** argv){ int fd=open("sharedFile",O_CREAT|O_RDWR|O_TRUNC,0600); if(fork()==0){ char buf[1000]; while(1) { // 读之前移到文件开头 lseek(fd, 0, SEEK_SET); readLine(fd, buf); if (buf[0] != '\0') { printf("%s\n",buf); } usleep(100000); } }else{ while(1){ sleep(1); // 写之前移到文件开头,覆盖旧内容 lseek(fd, 0, SEEK_SET); write(fd,"abcd",strlen("abcd")+1); } } }
两种方案都可以实现你要的每隔1秒输出一次abcd的效果。
内容的提问来源于stack exchange,提问作者giggiox
相关产品推荐
相关产品推荐

