簡體   English   中英

管,叉和執行 - 父母與子女過程的雙向溝通

[英]Pipe, Fork, and Exec - Two Way Communication Between Parent and Child Process

我的操作系統類中的賦值要求我通過在同一程序上遞歸調用exec來構建二進制進程樹。 目標是將一些任意任務拆分為單獨的進程。 父母應該通過未命名的管道與孩子和父母進行交流。 這個想法是父母將每個孩子的一半工作發送,並且這繼續遞歸,直到滿足基本案例,其中傳遞給每個孩子的字符串的長度<= 2.然后孩子處理這些數據並將結果發回通過管道給父母。

為了更好地理解雙向通信如何與c中的管道一起工作,我在繼續實際分配之前創建了以下簡單程序。 父節點從不從子進程讀取數據。 我期待輸出......

在父母| 收到的消息:測試

相反,當我打印時,我得到......

在父母| 收到消息:

似乎buff是空的,而不是從子進程中讀取。 有人可以解釋我做錯了什么和/或標准方式

  1. 寫給父母的exec'd孩子
  2. 從exec'd孩子的父母那里讀書
  3. 從exec'd孩子寫回父母
  4. 從父母的執行孩子那里讀書

我需要使用exec(),pipe(),fork()。 謝謝。

/**
 * *********************************
 * two_way_pipes.c
 * *********************************
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h> 
#include <sys/types.h> 
#include <unistd.h>

#define PARENT_READ read_pipe[0]
#define PARENT_WRITE write_pipe[1]
#define CHILD_WRITE read_pipe[1]
#define CHILD_READ  write_pipe[0]

#define DEBUGGING 1

int main(int argc, char **argv) {
    char buff[5];

    // in the child process that was exec'd on the orginal call to two_way_pipes
    if(argc == 2) {
        read(STDIN_FILENO, buff, 4); // this should read "test" from stdin
        buff[4] = '\0';
        fprintf(stdout, "%s\n", buff); // this should right "test" to stdout and be read by the parent process
    // int the root process, the original call to two_way_pipes with no args
    } else {
        int pid;
        int read_pipe[2];
        int write_pipe[2];

        pipe(read_pipe);
        pipe(write_pipe);

        pid = fork();

        // parent process
        if(pid > 0) {
            close(CHILD_READ);
            close(CHILD_WRITE);

            write(PARENT_WRITE, "test", 4); // attempting to write this to the child

            struct timeval tv;
            fd_set readfds;
            tv.tv_sec = 10;
            tv.tv_usec = 0;
            FD_ZERO(&readfds);
            FD_SET(PARENT_READ, &readfds);
            select(PARENT_READ + 1, &readfds, NULL, NULL, &tv);

            if(FD_ISSET(PARENT_READ, &readfds)) {
                read(PARENT_READ, buff, 4); // should read "test" which was written by the child to stdout
                buff[4] = '\0';
                close(PARENT_READ);
                close(PARENT_WRITE);
                fprintf(stderr, "in parent | message received: %s\n", buff);  // "test" is not in buff
            }

        // child process
        } else if(pid == 0) {
            close(PARENT_READ);
            close(PARENT_WRITE);

            dup2(CHILD_READ, STDIN_FILENO);
            dup2(CHILD_WRITE, STDOUT_FILENO);
            close(CHILD_READ);
            close(CHILD_WRITE);

            char *argv2[] = {"some random arg to make sure that argc == 2 in the child", NULL};
            execvp("two_way_pipes", argv2);
            _exit(0);
        // error forking child process
        } else {
            fprintf(stderr, "error forking the child\n");
        }
    }
}

更新

根據Jonathon的回答,我修改了傳遞給execvp的arg2數組到......

char *argv2[] = {"two_way_pipes", "1", NULL};
execvp("two_way_pipes", argv2);

這並沒有解決問題。 父母仍然無法從客戶端讀回“測試”。 然而,為了回應喬納森的回答和威廉的評論,我開始調整我的執行電話,並且出於某種原因將其更改為下面的線下節目。

execl("two_way_pipes", "two_way_pipes", "1", NULL);

我很樂意接受任何解釋,解釋為什么execvp調用不起作用,但execl調用。

除了Jonathon Reinhart 提到的問題之外,很可能對execv()的調用失敗了。

要測試這個修改這些行

execvp("two_way_pipes", argv2);
_exit(0);

成為

...
#include <errno.h>
...


execvp("two_way_pipes", argv2); /* On sucess exec*() functions never return. */
perror("execvp() failed); /* Getting here means execvp() failed. */
_exit(errno);

期待收到

execvp() failed: No such file or directory

要修復此更改

execvp("two_way_pipes", argv2);

成為

execvp("./two_way_pipes", argv2);

如果孩子不是exec*() ed那么這一行

read(PARENT_READ, buff, 4); // should read "test" which was written by the child to stdout

失敗,反過來buff沒有初始化,因此這一行

fprintf(stderr, "in parent | message received: %s\n", buff);  

挑起未定義的行為。

要解決這個問題,至少要通過更改來正確初始化buff

char buff[5];

成為

char buff[5] = "";

argv2的第一個條目應該是可執行文件的名稱(就像傳入的argv[0]

char *argv2[] = {"two_way_pipes", "some random arg...", NULL};
execvp("two_way_pipes", argv2);

execvp手冊頁

execv()execvp()execvpe()函數提供指向以null結尾的字符串的指針數組,這些字符串表示新程序可用的參數列表。 按照慣例,第一個參數應指向與正在執行的文件關聯的文件名。 指針數組必須由NULL指針終止。

正如Jonathon Reinhart所說,你應該改變這句話:

char *argv2[] = {"some random arg to make sure that argc == 2 in the child", NULL};
execvp("two_way_pipes", argv2);

至:

char *argv2[] = {argv[0], "some random arg...", NULL};
execvp(argv[0], argv2);

然后它按預期工作:

echo test | ./two_way_pipes
in parent | message received: test

在你的程序中你寫了“two_way_pipes”,但它不在你的PATH中所以你真的需要額外的./所以argv [0]然后是(“./two_way_pipes”)。

暫無
暫無

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

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