我正在为学校制作一个程序,我有一个多进程程序,每个进程读取一个文件的一部分,它们一起工作来计算文件中的单词数。我有一个问题,如果有超过2个进程,那么所有进程在读取文件的部分之前从文件中读取EOF。这是相关的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[]) {
FILE *input_textfile = NULL;
char input_word[1024];
int num_processes = 0;
int proc_num = 0; //The index of this process (used after forking)
long file_size = -1;
input_textfile = fopen(argv[1], "r");
num_processes = atoi(argv[2]);
//...Normally error checking would go here
if (num_processes > 1) {
//...create space for pipes
for (proc_num = 0; proc_num < num_processes - 1; proc_num++) {
//...create pipes
pid_t proc = fork();
if (proc == -1) {
fprintf(stderr,"Could not fork process index %d", proc_num);
perror("");
return 1;
} else if (proc == 0) {
break;
}
//...link up the pipes
}
}
//This code taken from http://stackoverflow.com/questions/238603/how-can-i-get-a-files-size-in-c
//Interestingly, it also fixes a bug we had where the child would start reading at an unpredictable place
//No idea why, but apparently the offset wasn't guarenteed to start at 0 for some reason
fseek(input_textfile, 0L, SEEK_END);
file_size = ftell(input_textfile);
fseek(input_textfile, proc_num * (1.0 * file_size / num_processes), 0);
//read all words from the file and add them to the linked list
if (file_size != 0) {
//Explaination of this mess of a while loop:
// if we're a child process (proc_num < num_processes - 1), then loop until we make it to where the next
// process would start (the ftell part)
// if we're the parent (proc_num == num_processes - 1), loop until we reach the end of the file
while ((proc_num < num_processes - 1 && ftell(input_textfile) < (proc_num + 1) * (1.0 * file_size / num_processes))
|| (proc_num == num_processes - 1 && ftell(input_textfile) < file_size)){
int res = fscanf(input_textfile, "%s", input_word);
if (res == 1) {
//count the word
} else if (res == EOF && errno != 0) {
perror("Error reading file: ");
exit(1);
} else if (res == EOF && ftell(input_textfile) < file_size) {
printf("Process %d found unexpected EOF at %ld.\n", proc_num, ftell(input_textfile));
exit(1);
} else if (res == EOF && feof(input_textfile)){
continue;
} else {
printf("Scanf returned unexpected value: %d\n", res);
exit(1);
}
}
}
//don't get here anyway, so no point in closing files and whatnot
return 0;
}
使用3个进程运行文件时的输出:
All files opened successfully
Process 2 found unexpected EOF at 1323008.
Process 1 found unexpected EOF at 823849.
Process 0 found unexpected EOF at 331776.
导致错误的测试文件:isin
编译:
gcc main.c -o wordc-mp
并以:
运行wordc-mp test34.txt 3
值得注意的是,只有那个特定的文件会给我带来问题,但错误的偏移量会不断变化,因此它不是文件的内容。
答案 0 :(得分:3)
您在分叉之前已经创建了文件描述符。子进程继承文件描述符,它指向父对象的文件描述,因此,与其中一个子进行前进会使所有子进程前进。
从&#34; man fork&#34;,您可以得到确认:
子进程是使用单个线程创建的 - 一个 那 叫fork()。父级的整个虚拟地址空间是 复制在孩子身上,包括互斥状态,状况 变量和其他pthreads对象;使用pthread_atfork(3) 可能有助于解决这可能导致的问题。
孩子继承了父母的一组开放文件描述 - 职权范围。子中的每个文件描述符都指向相同的open 文件描述(参见open(2))作为相应的文件描述符 在父母。这意味着两个描述符共享打开文件 状态标志,当前文件偏移和信号驱动的I / O属性 (参见fcntl(2)中F_SETOWN和F_SETSIG的描述)。