子进程输出重复数字的问题及解决方法咨询
问题描述
尝试为每个内循环创建一个子进程,但始终得到重复的执行结果。推测是由于每次迭代后创建的子进程都会访问同一个文件读取相同的数据。请问如何阻止它们获取重复的数字?data.txt文件中仅包含一个整数1:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { FILE *fptr; int N, i, j; //each of the process obtaining 200 integers from file a.txt pid_t pid; for(i=0;i<200;i++) { //loop for performing the given 8 steps by each process for(j=1;j<4;j++){ pid= fork(); fptr = fopen("data.txt","r");//step 1 fscanf(fptr,"%d",&N);//step 2 fclose(fptr);//step 3 printf("N=%d ProcessId=P%d\n", N, j);//step 4 N=N+1;//step 5 fptr = fopen("data.txt","w");//step 6 fprintf(fptr,"%d",N);//step 7 fclose(fptr);//step 8 } } return 0; }
问题分析与解决方案
核心问题
- 无同步的文件访问:多个子进程同时读取
data.txt时,没有任何同步机制,导致它们都读到文件的初始值,然后各自加1再写回,最终文件数值只增加1,但多个进程输出了相同的N值。 - fork后的执行逻辑混乱:
fork()后父子进程都会继续执行后续所有代码,包括后续循环和文件操作,导致进程数量爆炸,大量进程同时争抢文件资源。
具体解决步骤
1. 给文件加锁实现同步
使用文件锁(flock)确保同一时间只有一个进程能读取和修改文件,避免并发访问导致的重复读取,需要引入<sys/file.h>头文件。
2. 控制子进程的执行流程
fork()后立即判断进程身份:
- 子进程:执行完文件读写操作后立即退出,避免继续执行后续循环。
- 父进程:等待子进程完成后再继续,防止僵尸进程,同时保证内循环的进程依次执行,避免并发争抢。
修改后的代码示例
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/file.h> #include <sys/wait.h> int main() { FILE *fptr; int N, i, j; pid_t pid; for(i=0; i<200; i++) { for(j=1; j<4; j++){ pid = fork(); if(pid == -1) { perror("fork failed"); exit(EXIT_FAILURE); } else if(pid == 0) { // 子进程逻辑 // 用r+模式打开文件,减少文件操作次数 fptr = fopen("data.txt", "r+"); if(fptr == NULL) { perror("fopen failed"); exit(EXIT_FAILURE); } // 加排他锁,阻止其他进程访问 if(flock(fileno(fptr), LOCK_EX) == -1) { perror("flock failed"); fclose(fptr); exit(EXIT_FAILURE); } // 读取并修改数值 fscanf(fptr, "%d", &N); printf("N=%d ProcessId=P%d\n", N, j); N += 1; // 移动指针到文件开头,覆盖写入并强制刷盘 fseek(fptr, 0, SEEK_SET); fprintf(fptr, "%d", N); fflush(fptr); // 解锁并关闭文件 flock(fileno(fptr), LOCK_UN); fclose(fptr); // 子进程执行完成后退出 exit(EXIT_SUCCESS); } else { // 父进程等待子进程结束 wait(NULL); } } } return 0; }
关键改进点说明
r+模式打开文件:代替先读再写的两次打开操作,减少IO开销与同步风险。- 排他锁
LOCK_EX:确保当前进程读写时,其他进程必须等待锁释放才能访问文件。 fseek与fflush:写入前将指针移到文件开头,强制刷盘保证数据写入磁盘,避免缓存导致的不一致。- 子进程退出与父进程等待:保证内循环进程依次执行,避免并发争抢,同时消除僵尸进程。
内容的提问来源于stack exchange,提问作者Steve Ton
相关产品推荐
相关产品推荐

