我正在嘗試編寫以下2部分程序。在一個文件(「root.c」)中,我用一個1和0的隨機字符串讀取。然後我將結果字符串分成兩半,並通過fork()將每個半部分發送到自己的進程中。每個子進程使用execl()來運行第二個程序(「bit_count.c」)。C - 使用管道,選擇,分叉和execl創建進程樹
在bit_count.c中,它: a)檢查(半)串的長度是否等於或小於2。如果是,則返回
1和0的數字到它的父進程。 b)如果沒有,它開始遞歸地將字符串分成兩半,並將每一半發送到它自己的新進程(在root.c中複製該過程)。這會創建一個二進制進程樹,直到所有的字符串都是2個字符或更少。 c)左邊和右邊兒童的計數結果由家長彙總,並返回給其父母,直到返回聚合最高兩個子女的根進程,並將其輸出給用戶。
我與這個項目的問題是將2個字符的計數返回給父項。我現在的想法是將父母的左右讀取管道用dup2()指向標準輸入,並且只是用孩子的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;
}
}
感謝您的回覆!我將這行添加到了每個分叉的子級,並且在bit_count的末尾添加了write()調用。雖然輸出現在至少說我收到8個字節,但我仍然收到不可能的數字(例如,01和01,我得到每個孩子0和5的計數,而不是1和1。我知道bit_count計數正確,接收它仍然有問題。我應該從父母的閱讀管道中刪除dup2(他們在我的原始代碼中)?另外,不幸的是execl需要使用。謝謝你的幫助! – user2865485
你還在讀這樣的:'read(fd_left [0],&left_res,1);'?一對夫婦的問題:left_res被聲明爲一個指向int的指針,所以當你執行&left_res時,你會得到指針指向int的指針。你最好聲明'int left_res;',或者可能'int left_res [2];'。另外,你告訴'read'只讀1個字節。如果每個孩子正在寫兩個整數,你還需要在父母中讀取這個數額。 –
太棒了,謝謝!這個伎倆! – user2865485