我有一个程序从随机访问文件中读取,并将返回文件中的最小和最大数字。一个要求是,这是通过使用fork()的4个过程并将结果通过管道传递完成的。我将文件分为4个块,并让每个进程评估文件的一个块。我找到每个块的最大值和最小值,并将它们写入管道。最后,我将比较管道值并找到最大和最小的值。
我在从管道读取-1时遇到麻烦。对我在做什么错有任何见解?谢谢!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int findMin(int start, int end, const char * filename);
int findMax(int start, int end, const char * filename);
//Calculates minimum and maximum of a number
int main(int argc, char * argv[])
{
const char * filename; // name of file to read
FILE * ft; // file handle for the file
int pid, // process id of this process
num, // the number of integer values in the file
i, // loop control variable for reading values
temp=0; // used to store each value read from the file
long size; // size in bytes of the input file
/*********************************************************************/
filename = argv[1]; // read the file named on the command line
ft= fopen(filename, "rb");
if (ft)
{
pid = getpid();
fseek (ft,0,SEEK_END); //go to end of file
size = ftell(ft); //what byte in file am I at?
fseek (ft,0,SEEK_SET); //go to beginning of file
num = (int)size / (int)sizeof(int); // number of integer values
printf("file size: %li bytes\n", size);
printf("sizeof(int) = %i bytes\n",(int) sizeof(int));
printf("how many integers = %i\n\n", num);
fclose(ft);
}
//Split file size into quarters to make 4 processes
int increment = num/4;
int num1 = increment;
int num2 = num1 + increment;
int num3 = num2 + increment;
int num4 = num;
int status;
int pid1 = -1;
int pid2 = -1;
//Pipes
int fdmin1[2];
int fdmax1[2];
int fdmin2[2];
int fdmax2[2];
int fdmin3[2];
int fdmax3[2];
int fdmin4[2];
int fdmax4[2];
//initializing pipes
if(pipe(fdmin1) == -1)
{
perror("Piping fd1 failed");
return 0;
}
if(pipe(fdmax1) == -1)
{
perror("Piping fd2 failed");
return 0;
}
if(pipe(fdmin2) == -1)
{
perror("Piping fd3 failed");
return 0;
}
if(pipe(fdmax2) == -1)
{
perror("Piping fd4 failed");
return 0;
}
if(pipe(fdmin3) == -1)
{
perror("Piping fd3 failed");
return 0;
}
if(pipe(fdmax3) == -1)
{
perror("Piping fd4 failed");
return 0;
}
if(pipe(fdmin4) == -1)
{
perror("Piping fd3 failed");
return 0;
}
if(pipe(fdmax4) == -1)
{
perror("Piping fd4 failed");
return 0;
}
//temp variables for pipes
int temp1;
int temp2;
int temp3;
int temp4;
int temp5;
int temp6;
int temp7;
int temp8;
pid1 = fork();
printf("pid1: %d \n", pid1);
if(pid1 > 0)
{
//Process 1
temp1 = findMin(0, num1, filename);
temp2 = findMax(0, num1, filename);
close(fdmin1[0]);
if(write(fdmin1[1], &temp1, sizeof(int)) == -1)
{
printf("Error writting to pipe");
}
close(fdmin1[1]);
close(fdmax1[0]);
if(write(fdmax1[1], &temp2, sizeof(int)) == -1)
{
printf("Error writting to pipe");
}
close(fdmax1[1]);
}
else if(pid1 == 0)
{
//Process 2
temp3 = findMin(num1, num2, filename);
temp4 = findMax(num1, num2, filename);
close(fdmin2[0]);
if(write(fdmin2[1], &temp3, sizeof(int)) == -1)
{
printf("Error writting to pipe");
}
close(fdmin2[1]);
close(fdmax2[0]);
if(write(fdmax2[1], &temp4, sizeof(int)) == -1)
{
printf("Error writting to pipe");
}
close(fdmax2[1]);
pid2 = fork();
printf("pid2: %d \n", pid2);
if(pid2 > 0)
{
//Process 3
temp5 = findMin(num2, num3, filename);
temp6 = findMax(num2, num3, filename);
close(fdmin3[0]);
if(write(fdmin3[1], &temp5, sizeof(int)) == -1)
{
printf("Error writting to pipe");
}
close(fdmin3[1]);
close(fdmax3[0]);
if(write(fdmax3[1], &temp6, sizeof(int)) == -1)
{
printf("Error writting to pipe");
}
close(fdmax3[1]);
}
else if(pid2 == 0)
{
//Process 4
temp7 = findMin(num3, num4, filename);
temp8 = findMax(num3, num4, filename);
close(fdmin4[0]);
if(write(fdmin4[1], &temp7, sizeof(int)) == -1)
{
printf("Error writting to pipe");
}
close(fdmin4[1]);
close(fdmax4[0]);
if(write(fdmax4[1], &temp8, sizeof(int)) == -1)
{
printf("Error writting to pipe");
}
close(fdmax4[1]);
}
}
//Close all pipe ends in all processes
close(fdmin1[0]);
close(fdmin1[1]);
close(fdmin2[0]);
close(fdmin2[1]);
close(fdmin3[0]);
close(fdmin3[1]);
close(fdmin4[0]);
close(fdmin4[1]);
close(fdmax1[0]);
close(fdmax1[1]);
close(fdmax2[0]);
close(fdmax2[1]);
close(fdmax3[0]);
close(fdmax3[1]);
close(fdmax4[0]);
close(fdmax4[1]);
//Wait for all processes to finish
int returnStatus;
waitpid(pid1, &returnStatus, 0);
int returnStatus2;
waitpid(pid2, &returnStatus2, 0);
//Make sure we are in parant process
if(pid1 > 0)
{
//Variables to compare min and max returned from processses
int min1;
int max1;
int min2;
int max2;
int min3;
int max3;
int min4;
int max4;
//read from pipe (error is occuring here)
close(fdmin1[1]);
if(read(fdmin1[0], &min1, sizeof(int)) == -1)
{
printf("Error reading");
}
close(fdmin1[0]);
printf("min1: %d \n", min1);
}
return 0;
}
//function to find the minimum in the file
int findMin(int start, int end, const char * filename)
{
int temp;
int smallestNum;
int i;
int length = end - start;
FILE * ft2;
ft2= fopen(filename, "rb");
fseek (ft2,start,SEEK_SET);
fread(&smallestNum,sizeof(int),1,ft2);
for(i = 0; i < length; i++)
{
fread(&temp,sizeof(int),1,ft2);
//printf("%d \n", temp);
if(temp < smallestNum)
{
smallestNum = temp;
}
/*
printf("%5i: %7i ",pid,temp);
if ((i+1)%5 == 0)
printf("\n");
*/
}
fclose(ft2);
printf("SmallestNum: %d \n", smallestNum);
return smallestNum;
}
//function to find maximum in file
int findMax(int start, int end, const char * filename)
{
int temp;
int largestNum;
int i;
int length = end - start;
FILE * ft3;
ft3= fopen(filename, "rb");
fseek (ft3,start,SEEK_SET);
fread(&largestNum,sizeof(int),1,ft3);
for(i = 0; i < length; i++)
{
fread(&temp,sizeof(int),1,ft3);
//printf("%d \n", temp);
if(temp > largestNum)
{
largestNum = temp;
}
/*
printf("%5i: %7i ",pid,temp);
if ((i+1)%5 == 0)
printf("\n");
*/
}
fclose(ft3);
printf("Largest Num: %d \n", largestNum);
return largestNum;
}
这里是用于生成随机访问文件的代码
/*
* This file generates a binary output file containing integers. It
* requires the output filename as a parameter and will take an
* argument indicating the number of values to generate as input.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define BIAS 0 // a bias value added to the numbers to "bias" the file
// contents to provide an offset to the min and max
int main(int argc, char * argv[]) {
const char * filename; // name of the output file
FILE * ft; // file handle for output file
int numtogen = 1000000; // default is to generate 1,000,000 numbers
int randomnum, i; // variables used in the loop generating numbers
if (argc<2) { // not enough arguments, need output file name
printf("Usage: gendata <filename> [number of numbers]\n");
return 1;
}
if (argc == 3) // optional third argument for number of numbers
numtogen = atoi(argv[2]);
filename=argv[1]; // use the filename entered to store numbers
srand(time(NULL)); // seed the random number generator
ft= fopen(filename, "wb") ;
if (ft) {
for (i = 0; i < numtogen; i++){
randomnum = rand() % numtogen + BIAS;
fwrite(&randomnum,sizeof(int),1,ft);
}
fclose(ft);
}
return 0;
}
我在从管道读取-1时遇到麻烦。对我在做什么错有任何见解?谢谢!
这是因为在main进程中,您关闭了两次管道,所以
printf("pid1: %d \n", pid1); if(pid1 > 0) { ... close(fdmin1[0]); <<< HERE
和
//Close all pipe ends in all processes close(fdmin1[0]); <<< HERE
所以关闭时会关闭它:
if(read(fdmin1[0], &min1, sizeof(int)) == -1)
在读入之前,请勿关闭fdmin1[0]
,但反之。
注意,您还要关闭两次fdmin1[1]
和fdmax1[0]
和fdmax1[1]
。
管道的用法非常奇怪,可能没有您想要的东西:
[fdmin1
是main进程与其自身之间的管道,main进程执行if(write(fdmin1[1], &temp1, sizeof(int)) == -1)
,随后执行if(read(fdmin1[0], &min1, sizeof(int)) == -1)
,以便该管道无用,并且min1
为temp1
main进程执行if(write(fdmax1[1], &temp2, sizeof(int)) == -1)
,但没有人读取该值,该管道无用,并且temp2 = findMax(0, num1, filename);
一无所获。
main处理子执行if(write(fdmin2[1], &temp3, sizeof(int)) == -1)
和if(write(fdmax2[1], &temp4, sizeof(int)) == -1)
以及if(write(fdmin3[1], &temp5, sizeof(int)) == -1)
和if(write(fdmax3[1], &temp6, sizeof(int)) == -1)
,但没有人读过,这四个管道是无用的,并且所有的最小/最大计算都没有做。 >
创建的第三个进程执行if(write(fdmin4[1], &temp7, sizeof(int)) == -1)
和if(write(fdmax4[1], &temp8, sizeof(int)) == -1)
是相同的,但是没有人读过,这两个管道是无用的,最小/最大计算是一无所有。
这意味着最后您在main进程中没有获得正确的最小/最大值,但是仅丢失了main
代码
进程和两个子进程,因此3个进程而不是4个,//Wait for all processes to finish int returnStatus; waitpid(pid1, &returnStatus, 0); int returnStatus2; waitpid(pid2, &returnStatus2, 0);
由所有子进程执行,因为您不必执行
exit
或return
。您还具有未定义的行为,因为您在进程之间存在竞争条件,执行方式取决于我在代码中的位置
usleep
是不同的。父进程必须在需要时等待其子进程的结束,而不是在适当的时候。请注意,您的进程编号是错误的,只有main
//process4
不存在,并且注释在进程2中。除了main进程外,您没有从文件的正确位置读取数据,因为对于findMin
和findMax,参数start对应于int 而不是文件中的位置,必须替换fseek (ft2,start,SEEK_SET); fseek (ft3,start,SEEK_SET);
作者
fseek (ft2,start*sizeof(int),SEEK_SET); fseek (ft3,start*sizeof(int),SEEK_SET);
您也(尝试)读了一个int
太多的事情int length = end - start; ... fread(&smallestNum,sizeof(int),1,ft2); for(i = 0; i < length; i++) { fread(&temp,sizeof(int),1,ft2);
例如替换循环有
for(i = 1; i < length; i++)
如果我使用选项-Wall
进行编译,则程序中还会有很多无用的变量:
bruno@bruno-XPS-8300:/tmp$ gcc -Wall -g p.c -o p
p.c: In function ‘main’:
p.c:250:16: warning: unused variable ‘max4’ [-Wunused-variable]
int max4;
^
p.c:249:16: warning: unused variable ‘min4’ [-Wunused-variable]
int min4;
^
p.c:248:16: warning: unused variable ‘max3’ [-Wunused-variable]
int max3;
^
p.c:247:16: warning: unused variable ‘min3’ [-Wunused-variable]
int min3;
^
p.c:246:16: warning: unused variable ‘max2’ [-Wunused-variable]
int max2;
^
p.c:245:16: warning: unused variable ‘min2’ [-Wunused-variable]
int min2;
^
p.c:244:16: warning: unused variable ‘max1’ [-Wunused-variable]
int max1;
^
p.c:48:12: warning: unused variable ‘status’ [-Wunused-variable]
int status;
^
p.c:20:8: warning: unused variable ‘temp’ [-Wunused-variable]
temp=0; // used to store each value read from the file
^
p.c:19:8: warning: unused variable ‘i’ [-Wunused-variable]
i, // loop control variable for reading values
^
p.c:17:8: warning: variable ‘pid’ set but not used [-Wunused-but-set-variable]
int pid, // process id of this process
^
bruno@bruno-XPS-8300:/tmp$
超出
您必须先检查argc的值才能进行filename = argv[1];
。
如果fopen(filename, "rb");
失败,则必须停止执行,当前您将继续执行未定义的行为。
注意,还可以使用管道数组而不是使用单独的变量来简化程序,从而允许您使用循环而不是if(pipe(fdmin1) == -1) ... if(pipe(fdmax4) == -1) ...
的序列。启动子进程是相同的,而不是复制代码,而是使用一个函数只编写一次。这样,您可以定义一个允许任意数量的子进程,而不是仅用于4个子进程。
回到陈述
我将文件分成4个块,并让每个进程评估文件的一个块
这是一个极端的情况,但是您必须处理文件太小而无法除以4的情况,这在您的建议中不是这样。
这通过4个过程完成
考虑main
进程是必须创建的4个3个孩子中的一个。但是,与让每个孩子创建另一个孩子相比,通过main流程创建三个孩子要简单得多,并且并行性要好一些。程序必须是简单,我已经说过你有很多变量,什么也没有,而且很多代码也是重复的,也:
拥有如此多的管道是没有用的,只有一个管道足以允许每个孩子发送它计算出的最小值/最大值,因为保证管道的读写操作是原子的,直到PIPE_BUF
(大于大小)之2 int
)
读取这么多次文件毫无用处,您可以同时搜索最小值和最大值。
最后是一个提案:
中生成1000000#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #define N 4 /* including the main process */ /* to send/receive result atomicaly through the pipe */ typedef struct { int min, max; } MinMax; void findMinMax(long offset, long n, FILE * fp, MinMax * minmax); //Calculates minimum and maximum of a number int main(int argc, char * argv[]) { const char * filename; // name of file to read FILE * fp; // file handle for the file long num; // the number of integer values in the file long size; // size in bytes of the input file long offset; // offset in file int pp[2]; // the unique pipe int pids[N-1]; MinMax minmax; int i; if (argc != 2) { fprintf(stderr, "Usage: %s <filename>\n", *argv); exit(-1); } filename = argv[1]; fp = fopen(filename, "rb"); if (fp == NULL) { perror("cannot open file"); exit(-1); } /* get file size */ if (fseek(fp, 0, SEEK_END) == -1) { //go to end of file perror("cannot fseek"); fclose(fp); /* also done automaticaly when exiting program */ exit(-1); } size = ftell(fp); //what byte in file am I at? num = size / sizeof(int); // number of integer values printf("file size: %li bytes\n", size); printf("how many integers = %li\n\n", num); if (num < N) { fprintf(stderr, "the input file is too small, it must contains at least %i int\n", N); fclose(fp); /* also done automaticaly when exiting program */ exit(-1); } //initializing pipe if(pipe(pp) == -1) { perror("Piping failed"); exit(-1); } offset = 0; for (i = 0; i != N-1; ++i) { pids[i] = fork(); switch (pids[i]) { case 0: /* child */ { FILE * fp2 = fopen(filename, "rb"); if (fp2 == NULL) { perror("child cannot open file"); exit(-1); } findMinMax(offset, num/N, fp2, &minmax); printf("min max child %d : %d %d\n", i, minmax.min, minmax.max); if (write(pp[1], &minmax, sizeof(minmax)) != sizeof(minmax)) { perror("Error writting to pipe"); exit(-1); } } exit(0); case -1: /* parent */ perror("Cannot fork"); exit(-1); default: /* parent, no error */ offset += (num/N)*sizeof(int); } } findMinMax(offset, (size - offset)/sizeof(int), fp, &minmax); printf("min max main : %d %d\n", minmax.min, minmax.max); for (i = 0; i != N-1; ++i) { int status; MinMax mm; if ((waitpid(pids[i], &status, 0) != -1) && (status == 0) && (read(pp[0], &mm, sizeof(mm)) == sizeof(mm))) { if (mm.min < minmax.min) minmax.min = mm.min; if (mm.max > minmax.max) minmax.max = mm.max; } else fprintf(stderr, "cannot get result for child %d\n", i); } printf("global min max : %d %d\n", minmax.min, minmax.max); return 0; } // function to find the minimum and maximum in the file // n > 1 void findMinMax(long offset, long n, FILE * fp, MinMax * minmax) { int v; if (fseek(fp, offset, SEEK_SET) == -1) { perror("cannot fseek"); exit(-1); } if (fread(&minmax->min, sizeof(minmax->min), 1, fp) != 1) { fclose(fp); /* also done automaticaly when exiting program */ perror("cannot read int"); exit(-1); } minmax->max = minmax->min; while (--n) { if (fread(&v, sizeof(v), 1, fp) != 1) { fclose(fp); /* also done automaticaly when exiting program */ perror("cannot read int"); exit(-1); } if (v < minmax->min) minmax->min = v; if (v > minmax->max) minmax->max = v; } fclose(fp); /* also done automaticaly when exiting program */ }
如您所见,代码非常简单,我只需要将
#define N 4
修改为其他值即可更改并行工作的进程数。使用第二个程序在aze
int
,编译并执行我的提案:bruno@bruno-XPS-8300:/tmp$ gcc -g -Wall p.c
bruno@bruno-XPS-8300:/tmp$ ./a.out aze
file size: 4000000 bytes
how many integers = 1000000
min max main : 2 999995
min max child 0 : 10 999994
min max child 2 : 0 999998
min max child 1 : 3 999999
global min max : 0 999999
bruno@bruno-XPS-8300:/tmp$