簡體   English   中英

C-使用管道,選擇,派生和執行創建進程樹

[英]C - creating process tree using pipes, select, fork, and execl

我正在嘗試編寫以下兩部分程序。 在一個文件(“ 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()函數應該捕獲返回的輸出,對嗎?

我的第二個問題是輸出的格式。 如果計數是整數,在這種情況下,使用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;
}
  } 
  1. 我現在的想法是使用dup2()將父級的左右讀取管道定向到stdin,而僅使用子級中的fprintf將其打印到stdout。 父級的select()函數應該捕獲返回的輸出,對嗎?

否。在調用execl()之前,您需要在子級中使用dup2(fd [1],STDOUT_FILENO)。 bit_count還應該如何了解管道? 然后,在父級中,您只能從fd [0]中讀取。 為了使事情變得簡單,您可以使bit_count一個函數,然后直接在子級中調用它,而無需使用execl()。 然后,您可以直接從子級寫入fd [1](如果將其設置為全局,或將值傳遞給bit_count函數)。

  1. 我的第二個問題是輸出的格式。 如果計數是整數,在這種情況下,使用select()返回該值的最佳方法是什么?

您可以使用write(STDOUT_FILENO, &counts, 2*sizeof(int))將整數直接寫入管道,而不必將其格式化為字符串。 這樣,父級無需將它們轉換回int。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM