[英]Reading from Pipe in C
我有一个程序从随机访问文件中读取,并返回文件中的最小和最大数字。 一个要求是使用 fork() 和管道传输结果通过 4 个进程完成。 我将文件分成 4 个块,并让每个进程评估文件的一个块。 我找到每个块的最大值和最小值并将它们写入 pipe。 最后,我将比较管道值并找到最大值和最小值。
当管道返回-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时,我无法从管道中读取。 关于我做错了什么的任何见解? 谢谢!
这是因为在主过程中你关闭了两次 pipe,做
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
是主进程和自身之间的 pipe,主进程执行if(write(fdmin1[1], &temp1, sizeof(int)) == -1)
和稍后if(read(fdmin1[0], &min1, sizeof(int)) == -1)
所以 pipe 没用, min1
是temp1
主进程执行if(write(fdmax1[1], &temp2, sizeof(int)) == -1)
但没有人读取该值, pipe 没用, temp2 = findMax(0, num1, filename);
是白做的。
主进程子进程执行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)
但没有人阅读,这两个管道没用,最小/最大计算是徒劳的。
这意味着最后你在主进程中没有得到正确的最小值/最大值,而只有主进程和所有其他计算的第一季度计算的最小值会丢失。
编码
//Wait for all processes to finish int returnStatus; waitpid(pid1, &returnStatus, 0); int returnStatus2; waitpid(pid2, &returnStatus2, 0);
由所有子进程执行,因为当你不得不做的时候你不会exit
或return
。
您还有一个未定义的行为,因为您的进程之间存在竞争条件,执行不一样,具体usleep
我在您的代码中使用的位置。 父进程必须在需要时等待其子进程的结束,而您却不是在正确的时刻。 注意你的进程编号是错误的,只有主进程和两个子进程,所以是 3 个进程而不是 4 个, //process4
不存在,并且注释在进程 2 中。
除了在主过程中您没有从文件中的右侧 position 读取,因为对于findMin和findMax参数start对应于int的等级而不是文件中的 position,您必须替换
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 too many doing
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$
从中
在执行filename = argv[1];
之前,您必须检查argc的值 .
如果fopen(filename, "rb");
失败你必须停止执行,目前你继续一个未定义的行为。
另请注意,您的程序可以使用 pipe 数组来简化,而不是为它们分隔变量,允许您使用循环而不是if(pipe(fdmin1) == -1)... if(pipe(fdmax4) == -1)...
的序列if(pipe(fdmin1) == -1)... if(pipe(fdmax4) == -1)...
启动子进程也是一样的,不要重复代码使用function只写一次。 这样做,您可以定义允许任意数量的子进程,而不是仅专用于 4 个。
回到声明
我将文件分成 4 个块,并让每个进程评估文件的一个块
这是一个极端情况,但您必须处理文件太小而不能被 4 整除的情况,您的提案中不是这种情况。
这是通过 4 个过程完成的
考虑到主进程在 4 个中,必须创建 3 个子进程。 但与其让每个子进程在需要时创建另一个子进程,不如让主进程创建 3 个子进程更简单,并且并行性更好一些。
一个程序必须很简单,我已经说过你有很多变量是无用的,而且很多代码是重复的,还有:
拥有这么多管道是没有用的,只有一个就足以让每个孩子发送它计算的最小值/最大值,因为 pipe 的读写保证是原子的,直到PIPE_BUF
(大于 2 int
的大小)
文件读了这么多次也没用,可以同时搜索最小值和最大值。
最后是一个建议:
#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中生成 1000000 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$
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.