我正在尝试编写一个C程序,它使用管道在父项和两个子项之间发送信息。该程序的目标是实现类似于合并排序的字符串。我读了字符串的数量,然后是字符串。字符串在两个子节点之间递归划分,直到每个子节点只有一个字符串。我必须重定向孩子的标准输入以从父母的标准输出读取。
由于某些原因,没有一个孩子读的比第一个字符串多。 我怎么能解决这个问题?
int main(int argc, char * argv[]) {
int nrrows = 0;
char * buffer = NULL;
size_t n = 0;
getline(&buffer, &n, stdin);
char * endptr;
nrrows = strtol(buffer, &endptr, 10);
char rows[nrrows][MAX_LEN];
int i = 0;
n = 0;
while(i < nrrows) {
char * row = NULL;
getline(&row, &n, stdin);
strcpy(rows[i], row);
i++;
}
if(nrrows == 1) {
fprintf(stderr, "%s", rows[0]);
return 0;
}
int fdcp1[2];
int fdcp2[2];
if(pipe(fdcp1) < 0) {
fprintf(stderr, "pipe unsuccessfull\n");
return EXIT_FAILURE;
}
if(pipe(fdcp2) < 0) {
fprintf(stderr, "pipe unsuccessfull\n");
return EXIT_FAILURE;
}
pid_t chpid1 = fork();
if(chpid1 < 0) {
fprintf(stderr, "fork unsuccessfull\n");
return EXIT_FAILURE;
}
else if(chpid1 == 0) {
close(fdcp2[0]);
close(fdcp2[1]);
close(fdcp1[1]);
dup2(fdcp1[0], STDIN_FILENO);
execlp("./forksort", "child1", NULL);
}else {
close(fdcp1[0]);
dup2(fdcp1[1], STDOUT_FILENO);
double half = (nrrows / 2);
int h = half;
char b[2];
b[0] = '0' + h;
b[1] = '\n';
write(fdcp1[1], b, sizeof(b));
for(i = 0; i < h; i ++) {
rows[i][strlen(rows[i])] = '\0';
write(fdcp1[1], rows[i], sizeof(rows[i]));
}
pid_t chpid2 = fork();
if(chpid2 < 0) {
fprintf(stderr, "fork unsuccessfull\n");
return EXIT_FAILURE;
}else if(chpid2 == 0) {
close(fdcp1[0]);
close(fdcp1[1]);
close(fdcp2[1]);
dup2(fdcp2[0], STDIN_FILENO);
execlp("./forksort", "child2", NULL);
}else {
close(fdcp2[0]);
dup2(fdcp2[1], STDOUT_FILENO);
half = (nrrows / 2);
h = half;
char b[2];
b[0] = '0' + (nrrows - h);
b[1] = '\n';
write(fdcp2[1], b, sizeof(b));
for(i = h; i < nrrows; i ++) {
rows[i][strlen(rows[i])] = '\0';
write(fdcp2[1], rows[i], sizeof(rows[i]));
}
}
}
return 0;
}
答案 0 :(得分:0)
修改与开放流关联的文件描述符是个坏消息。我认为它很可能会给你带来麻烦,而且这里也没有必要这样做。父母应该使用fdopen()
在管道末端打开新流,并通过它们而不是通过标准流与子代进行I / O.除了更安全之外,还使流程的原始标准流可用于与其父流程进行通信。
使用这种方法,您甚至可以流式传输字符串以在进程之间来回排序,而不是在每个进程的内存中冗余地缓冲它们的块。例如,您可能会这样做:
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char * argv[]) {
char * buffer = NULL;
size_t buflen = 0;
int nrrows;
int fdpc1[2];
int fdcp1[2];
int fdpc2[2];
int fdcp2[2];
pid_t chpid1;
pid_t chpid2;
FILE *pipeout;
FILE *pipein1;
FILE *pipein2;
int half;
int i;
fprintf(stderr, "%s!!!!!!!!!!!!!!!!!\n", argv[0]);
getline(&buffer, &buflen, stdin);
fprintf(stderr, "number: %s from %s\n", buffer, argv[0]);
nrrows = strtol(buffer, NULL, 10);
if(nrrows <= 0) {
fprintf(stderr, "This is not a valid >0 number\n");
return EXIT_FAILURE;
} else if (nrrows == 1) {
/* ... read and echo back the one row ... */
getline(&buffer, &buflen, stdin);
fprintf(stderr, "%s", buffer);
return EXIT_SUCCESS;
}
/* There are at least two rows to sort */
if (pipe(fdcp1) < 0) {
fprintf(stderr, "pipe unsuccessfull\n");
return EXIT_FAILURE;
}
if (pipe(fdpc1) < 0) {
fprintf(stderr, "pipe unsuccessfull\n");
return EXIT_FAILURE;
}
chpid1 = fork();
if (chpid1 == 0) {
/* this is child process 1 */
close(fdcp1[1]);
close(fdpc1[0]);
dup2(fdcp1[0], STDIN_FILENO);
close(fdcp1[0]);
dup2(fdpc1[1], STDOUT_FILENO);
close(fdpc1[1]);
execlp("./forksort", "child1", NULL);
} else if (chpid1 < 0) {
fprintf(stderr, "fork unsuccessfull\n");
return EXIT_FAILURE;
}
/* this is the parent process */
close(fdcp1[0]);
close(fdpc1[1]);
if (pipe(fdcp2) < 0) {
fprintf(stderr, "pipe unsuccessfull\n");
return EXIT_FAILURE;
}
if (pipe(fdpc2) < 0) {
fprintf(stderr, "pipe unsuccessfull\n");
return EXIT_FAILURE;
}
chpid2 = fork();
if (chpid2 == 0) {
/* this is child process 2 */
close(fdcp1[1]);
close(fdpc1[0]);
close(fdcp2[1]);
close(fdpc2[0]);
dup2(fdcp2[0], STDIN_FILENO);
close(fdcp2[0]);
dup2(fdpc2[1], STDOUT_FILENO);
close(fdpc2[1]);
execlp("./forksort", "child2", NULL);
} else if (chpid2 < 0) {
fprintf(stderr, "fork unsuccessfull\n");
return EXIT_FAILURE;
}
/* this is the parent process */
close(fdcp2[0]);
close(fdpc2[1]);
/* copy the first half of the lines from input to child 1 */
pipeout = fdopen(fdcp1[1], "w");
if (pipeout == NULL) {
fprintf(stderr, "fdopen unsuccessful\n");
return EXIT_FAILURE;
}
half = nrrows / 2;
fprintf(pipeout, "%d\n", half);
for (i = 0; i < half; i += 1) {
getline(&buffer, &buflen, stdin);
fprintf(stderr,"row[%d] from %s: %s", i, argv[0], buffer);
fputs(buffer, pipeout);
}
fclose(pipeout);
/* copy the second half of the lines from input to child 2 */
pipeout = fdopen(fdcp2[1], "w");
if (pipeout == NULL) {
fprintf(stderr, "fdopen unsuccessful\n");
return EXIT_FAILURE;
}
fprintf(pipeout, "%d\n", nrrows - half);
for (; i < nrrows; i += 1) {
getline(&buffer, &buflen, stdin);
fprintf(stderr,"row[%d] from %s: %s", i, argv[0], buffer);
fputs(buffer, pipeout);
}
fclose(pipeout);
/* now read and merge sorted lines from the children */
pipein1 = fdopen(fdpc1[0], "r");
pipein2 = fdopen(fdpc2[0], "r");
if (pipein1 == NULL || pipein2 == NULL) {
fprintf(stderr, "fdopen unsuccessful\n");
return EXIT_FAILURE;
}
/* ... */
fclose(pipein1);
fclose(pipein2);
return 0;
}