我正在尝试编写以下2部分程序。在一个文件(“root.c”)中,我读入1和0的随机字符串。然后我将结果字符串分成两半,并通过fork()将每一半发送到自己的进程。每个子进程使用execl()来运行第二个程序(“bit_count.c”)。
在bit_count.c中,它:
a)检查(半)弦的长度是否为2或更小。如果是,则返回
的数量
1和0是它的父进程。
b)如果没有,它开始递归地将字符串分成两半,并将每一半发送到它自己的新进程(在root.c中复制该过程)。这将创建一个二进制进程树,直到所有字符串长度为2个字符或更少。
c)左右子项的计数结果由父项聚合,并返回到其父项,直到返回到根过程,该过程聚合最高的两个子项,并将其输出给用户。
我对这个项目的问题是将2个字符的计数返回给父项。我现在的想法是将父母的左右读取管道指向带有dup2()的stdin,然后用来自子节点的fprintf打印到stdout。父对象的select()函数应该捕获返回的输出,对吧?
我的第二个问题是输出格式。如果计数是ints,在这种情况下使用select()返回的最佳方法是什么?我已经在下面添加了我的代码,只是被警告它可能是一团糟 - 我生锈了C代码,这是我第一次接触select()和execl()。
root.c:
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char* argv[]) {
if (argc != 2) {
perror("input file name");
printf("%d", argc);
exit(1);
}
FILE* fp;
if((fp = fopen(argv[1], "r")) == NULL) {
perror("open file");
}
fseek(fp, 0, SEEK_END);
long fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *bits = malloc(fsize+1);
fread(bits, fsize, 1, fp);
fclose(fp);
char *left_half = malloc( fsize/2 + 1 );
char *right_half;
if (fsize%2) right_half = malloc( fsize/2 + 2 );
else right_half = malloc( fsize/2 + 1 );
if (!left_half || !right_half) perror("array split");
memcpy(left_half, bits, fsize/2);
if (fsize%2) memcpy(right_half, bits + fsize/2, fsize/2 + 1);
else memcpy(right_half, bits + fsize/2, fsize/2);
int fd_left[2], fd_right[2];
int zero, one;
int *left_res, *right_res;
pid_t left, right;
struct timeval tv;
fd_set readfds;
tv.tv_sec = 2;
tv.tv_usec = 500000;
if ((pipe(fd_left) == -1) || (pipe(fd_right) == -1)){
perror("Create pipe error");
exit(1);
}
FD_ZERO(&readfds);
FD_SET(fd_left[0], &readfds);
FD_SET(fd_right[0], &readfds);
if ((left=fork()) == 0) {
close(fd_left[0]);
execl("./bit_count", "bit_count", left_half, NULL);
perror("initiating recursion");
exit(1);
}
else if(left > 0) {
if ((right = fork())==0) {
close(fd_right[0]);
execl("./bit_count", "bit_count", right_half, NULL);
perror("initiating recursion");
exit(1);
}
else if (right > 0) {
close(fd_right[1]);
close(fd_left[1]);
char *left;
char *right;
dup2(fd_left[0], 0);
dup2(fd_right[0], 0);
int ret = select(2, &readfds, NULL, NULL, &tv);
read(fd_left[0], &left_res, 1);
read(fd_right[0], &right_res, 1);
printf("Back in root process!\n");
}
}
zero = (*right_res + *left_res);
one = (*(left_res+sizeof(int)) + *(right_res+sizeof(int)));
printf("%s had %d zeroes and %d ones\n", argv[1], zero, one);
return 0;
}
bit_count.c(仅相关部分):
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
if (argc != 2) {
perror("sent bit string");
printf("%d", argc);
exit(1);
}
char *bit_string = argv[1];
int size = strlen(bit_string);
int counts[2];
counts[0] = 0;
counts[1] = 0;
if (!(size > 2)) {
int i=0;
for(; i < size; i++) {
if (bit_string[i]=='1') ++counts[1];
else ++counts[0];
}
fprintf(stdout, "%p", &counts);
fflush(stdout);
return 0;
}
}
答案 0 :(得分:1)
- 我现在的想法是将父母的左右读取管道指向带有dup2()的stdin,然后用来自孩子的fprintf打印到stdout。父对象的select()函数应该捕获返回的输出,对吗?
醇>
没有。在调用execl()之前,你需要在子节点中使用dup2(fd [1],STDOUT_FILENO)。如何知道bit_count有关管道的信息?然后在父母中你可以从fd [0]中读取。为了简化操作,您可以将bit_count作为一个函数,并在不使用execl()的情况下直接在子函数中调用它。然后你可以从孩子那里写fd [1](如果你把它设为全局,或者将值传递给bit_count函数)。
- 我的第二个问题是输出的格式。如果计数是整数,那么在这种情况下使用select()返回的最佳方法是什么?
醇>
您可以使用write(STDOUT_FILENO, &counts, 2*sizeof(int))
将int直接写入管道,而不是将它们格式化为字符串。这样父级不需要将它们转换回int。