IPC 新手,无法让我的管道正常工作

Posted

技术标签:

【中文标题】IPC 新手,无法让我的管道正常工作【英文标题】:New to IPC, can't get my pipe to work 【发布时间】:2013-10-22 23:42:45 【问题描述】:

很抱歉这篇文章的长度......我在这方面遇到了无数问题。前面我会说我是一名学生,我的教授是一个毫无价值的资源。所以,我要做的就是让生产者分叉,然后父生产者将计算文件中的一些内容并将两个整数发送给消费者,消费者是由子进程启动的。我已经测试了所有东西,fork 和文件的东西都可以工作,而且我到处都有 printf 语句,所以我知道正在做什么以及代码在哪里。

当我添加了

if (pipe(pipefd) == -1) 
   perror("pipe");

它导致我的父母刚刚终止。它达到“父管道打开”但随后死亡。我用 $ ps 检查它是否刚刚挂起,但它不存在;它只是死了。如果我把那个 sn-p 拿出来,它会运行到最后,但我认为如果那个代码不存在,那么它实际上并不知道 pipefd 是一个管道......对吗?

我确实在此站点上进行了搜索,并找到了另一个示例,并按照他的做法以及答案进行了操作,而我的只是拒绝工作。我很确定这是一件非常容易解决的事情,但我已经没有尝试什么的想法了:(

我真的不想发布我所有的代码,因为这将是一堵巨大的文字墙,但我也不想不小心删掉一些原来很重要的东西。

生产者.c

#include <stdio.h>      /* printf, stderr, fprintf */
#include <sys/types.h>  /* pid_t */
#include <unistd.h>     /* _exit, fork, execl */
#include <stdlib.h>     /* exit */
#include <errno.h>      /* errno */
#include <string.h>     /* strlen */
#include <sys/wait.h>   /* wait */

#define SLEEP_TIME 8

int main (int argc, char *argv[])
    //PID
    pid_t local_pid;
    local_pid = fork();

    //Logic to determine if the process running is the parent or the child
    if (local_pid == -1) 

        /* Error:
        * When fork() returns -1, an error happened
        * (for example, number of processes reached the limit).
        */
        fprintf(stderr, "can't fork, error %d\n", errno);
        exit(EXIT_FAILURE);

     else if (local_pid == 0) 

        //Child specific code
        int child;
        char *temp[] = NULL;
        printf("Child PID found\n");
        child = execv("./consumer", temp); 

        _exit(0);


     else 
        //Parent specific code
        printf("Parent running\n");
        //open file
        FILE * randStrings;
        randStrings = fopen("randStrings.txt", "r");
        int file_length;
        int num_of_e = 0;
        int c;          //using this as a char


        //until eof
        while (feof(randStrings) == 0) 
            c = fgetc(randStrings);
            //calculate length of file
            file_length++;
            //count e chars
            if (c == 'e') 
                num_of_e++;
            
        

        //close file
        fclose(randStrings);

        //send bundle to child
        int a[2];
        a[0] = num_of_e;
        a[1] = file_length;

        printf("num of e = %i\n", a[0]);
        printf("len = %i\n", a[1]);

        //set up parent pipe
        int pipefd[2];

        if (pipe(pipefd) == -1) 
            perror("pipe");
            printf("x\n");
        
        printf("parent pipe open\n");
        close(pipefd[0]); //close the read end
        write(pipefd[1], &a[0], sizeof(int));
        write(pipefd[1], &a[1], sizeof(int));
        close(pipefd[1]);
        printf("parent pipe closed\n");

        //wait for child to finish running
        wait(NULL);
        printf("parent out\n");
        //terminate
    

和消费者.c

#include <stdio.h>      /* printf, stderr, fprintf */
#include <sys/types.h>  /* pid_t */
#include <unistd.h>     /* _exit, fork, execl */
#include <stdlib.h>     /* exit */
#include <errno.h>      /* errno */

#define SLEEP_TIME 5

int main (int argc, char *argv[])

    sleep(SLEEP_TIME);
    printf("Child program launched\n");

    //receive bundle
    int pipefd[2];
    int buf[2]; 

    if (pipe(pipefd) == -1) 
        perror("pipe");
        printf("child x\n");
    

    close(pipefd[1]); //child closes write end

    buf[0] = 0;
    buf[1] = 0;

    /*int i = 0;        // i dont like this
    while (read(pipefd[0], &buf[i], sizeof(int)) > 0) 
        i++;
    */
    printf("child reading pipe\n");

    read(pipefd[0], &buf[0], sizeof(int));
    read(pipefd[0], &buf[1], sizeof(int));

    close(pipefd[0]);
    //buf should have the stuff in it
    int num_of_e = buf[0];
    int file_length = buf[1];
    printf("child num of e = %i\n", num_of_e);
    printf("child len = %i\n", file_length);

    //open file
    FILE * resultStrings;
    resultStrings = fopen("resultStrings.txt", "w");

    for (int i = 0; i < num_of_e; i++) 
        //write num_of_e e chars
        fputc('e', resultStrings);
    
    //or if no e chars, write - chars
    if (num_of_e == 0) 
        for (int i = 0; i < file_length; i++) 
            //write file_length '-' chars
            fputc('-', resultStrings);
        
    
    //close file
    fclose(resultStrings);
    printf("child out\n");

如果你仍然在这里,你应该感谢你,因为这篇文章太长了。

【问题讨论】:

教授是一文不值的资源这是否意味着他/她从不看SO? @ryyker 你认为他知道 user2867890 是谁吗? @JonathonReinhart - 哈哈,可能不是。 (但很容易找到像这个问题一样具体的问题。)我发现一般来说,以这种方式提及他们的教授(或其他任何人)的学生应该照照镜子。 (顺便说一句,答案很好,+1) 【参考方案1】:

你做错了。整个机制之所以有效,是因为子进程继承了父进程的打开文件描述符。

应该是这样的:

pipe(pipefd)打开管道 fork() 父(生产者): 关闭读取端 (pipefd[0]) 写入写入端 (pipefd[1]) 儿童(消费者): 关闭写入端 (pipefd[1]) 从读取端读取 (pipefd[0])         调用 exec

您正在父进程和子进程中打开不同的管道(在您 forked 之后)。它需要在您 fork 之前发生。

既然你是execing,新进程需要知道只读管道。有几种方法可以做到这一点:

在命令行中将文件描述符号 (pipefd[0]) 传递给它 dup2(1, fd) 它是新执行进程的标准输入

【讨论】:

好吧,大部分都是有道理的。所以在执行之后,消费者不知道管道在那里,但我不需要打开它......只需使用 read(3, foo, bar);对吗? 对 - pipefd[0]可能是 3。但是,并不能真正保证这一点。这就是为什么我建议在命令行上传递它。 我们的老师也没有教我们如何正确使用 exec(基本上我们从来没有被教过 C,我们被教过 Java 并且这个家伙,尽管正确,认为我们需要学习 C 所以他在没有任何指导或帮助的情况下将我们所有的作业都用 C 分配)。所以我很不清楚我将如何通过命令行...“./consumer -something”?然后用 argv[somethingelse] 访问它? 查看man page for execv 提示:你已经没有通过它了。 (char *temp[] = NULL;) 搜索“c 命令行参数”将我带到***.com/questions/3337915/…。

以上是关于IPC 新手,无法让我的管道正常工作的主要内容,如果未能解决你的问题,请参考以下文章

查找管道内的 ObjectId 匹配无法正常工作

角度日期管道在文本框中无法正常工作

在 Azure DevOps 中使用构建管道运行 Google 测试

带有 SkLearn 管道的 GridSearch 无法正常工作

嵌套在 ngIf 中时,异步管道订阅无法正常工作

文件系统中的命名管道不是很慢吗?