与管子和叉子的C家庭作业

时间:2016-12-13 00:21:37

标签: c pipe fork

大家好,

我在学校的家庭作业中完全迷失了,因为他们还没有告诉我们很多相关内容,而且我之前没有做过类似的事情。

任务是:

在C语言中创建一个程序,创建两个进程(fork函数)并通过管道(管道函数)连接它们。 第一个后代重新定向了它的' stdout进入管道并将(空格分隔的)成对的随机数写入其中(函数rand)。 延迟数字的输出(即1秒)。

第一个后代有 处理SIGUSR1信号(sigaction函数),并且在接收到这样的信号的情况下,它将字符串“TERMINATED”打印到它的stderr并终止。

第二个后代将管道输出重定向到它的stdin,将它的stdout重定向到名为out.txt的文件中 当前目录并执行一个二进制文件(execl函数)来查找最大公约数(我们以前的任务的输出,我们必须编写一个运行一个小C程序的makefile来检测一个数字是否为素数)。

父进程等待5秒,然后将SIGUSR1发送到第一个进程(数字生成器)。这应该执行两个进程的正确终止。它等待子进程终止(等待函数)并终止自身。

实际上你正在实现这样的事情:while :;回声$ RANDOM $ RANDOM;睡1;完成| ./c1_task> out.txt

我绝对迷失在此,到目前为止我一点也不幸。 我不知道从哪里开始。

有人可以告诉我什么吗?

提前致谢!

1 个答案:

答案 0 :(得分:2)

由于我不相信让人们为他们工作,我无法为您提供解决方案。"但是,我可以向您展示完成作业时需要了解的一些概念。我也可以给你一些链接,但是如果你只是寻求你不了解的概念的帮助,你很可能会找到你需要的信息。

现在我已经提供了一段介绍性信息,我将帮助您完成解决此问题所需了解的一些概念。
我可能会填写一些遗漏的信息,如果我得到(并且觉得它值得花费)将这个变成伪教程所需的时间。 :)

所提供的信息可能会简化,有点含糊,或者可能会有所改进。亲爱的读者,如果您发现问题,请随时告诉我。

第一个概念:fork() - ing

它是什么? fork()通过将当前流程(大部分)复制到另一个流程,可以轻松地同时执行多项操作。 (实际上,它类似于asexual reproduction.

例如,进程(这是通过进行fork()系统调用创建的新进程)继承了打开的文件描述符(这是一个重点!),它自己的父进程(拥有/拥有)等变量的副本。

示例:这是一个示例程序,用于说明一两件事。请注意wait()。它使父进程调用fork(),等待继续执行程序的其余部分,直到子进程终止。如果没有wait(NULL),我们就无法保证父亲的printf语句会在孩子的printf语句之后运行。

#include <stdio.h> //the usual, perror
#include <stdlib.h> //exit
#include <sys/types.h> //wait() / pid_t
#include <sys/wait.h> //wait()
#include <unistd.h> // fork()

int main () {
    pid_t cpid;

    //create our child.
    //fork() returns -1 if the fork failed, otherwise it returns
    //    the pid of the child to the parent,
    //    and 0 to the child
    cpid = fork();

    //Both the child process and parent process executed the
    //"cpid =" assignment.
    //However, they both modified their own version of cpid.
    //From now on, everything is run by both the child and parent.

    //the fork failed; there is no child so we're done.
    if (cpid < 0) {
        perror("During attempted fork");
        exit(EXIT_FAILURE);
        }

    //Though the if statement will be checked by both,
    //cpid will equal 0 only in the child process.
    if (cpid == 0) {
        //This will be executed by the child.
        printf("Hello. I'm your child.\n");

        //Now that we've let Pops know that we're alive...
        exit(EXIT_SUCCESS);
        }

     else if (cpid > 0) {
        //wait for our child to terminate.
        //I dare you to comment this out & run the program a few times.
        //Does the parent ever print before the child?
        wait(NULL);

        printf("I proudly parented 1 child.\n");
        }

     return 0;
     }

其他:您可以看到另一个示例here.

第二个概念:管道

什么是管道?管道是进程间通信的方法。基本上,它有一端可以放入数据(write()是一种方法)和一端可以获取数据(使用read)。

使用pipe()系统调用创建管道。它出错时返回-1。它唯一的参数是两个整数数组的地址,我们称之为pipe_fds

如果调用成功,pipe_fds中的第一个元素包含用于从管道读取的file descriptor;第二个元素包含用于写入管道的file descriptor

您可以使用write()写入管道,并使用read()从管道中读取。 (有关使用管道的更多信息,请参见various places

上的the internet.

以下是一个例子:

#include <stdio.h> //the usual, perror
#include <stdlib.h> //exit
#include <sys/types.h> //wait() / pid_t
#include <sys/wait.h> //wait()
#include <unistd.h> // fork(), pipe()

#define BUFLEN 256 //must be greater than one

int main () {
    int pipe_fds[2],
        pipe_ret;
    pid_t cpid;

    //Let's create a pipe.
    //Note that we do this *before* forking so that our forked child
    //    has access to the pipe's file descriptors, pipe_fds.
    pipe_ret = pipe(pipe_fds);

    //we couldn't create our pipe
    if (pipe_ret == -1) {
        perror("Pipe Creation");
        exit(EXIT_FAILURE);
        }

    //create our child.
    cpid = fork();

    //the fork failed; there is no child so we're done.
    if (cpid < 0) {
        perror("During attempted fork");
        exit(EXIT_FAILURE);
        }

    //Am I the child?
    if (cpid == 0) {
        //close the childs read end of the pipe.
        //Failing to close unused pipe ends is life or death!
        //(Check `man 7 pipe`)
        close(pipe_fds[0]);

        //Send a message through the pipe.
        //NOTE: For simplicity's sake, we assume that our printing works.
        //    In the real world, it might not write everything, etc.
        //We could use `write()`, but this way is easier.
        dprintf(pipe_fds[1], "Daddy, I'm alive.\n");

        //We're done writing. Close write end of the pipe.
        //This is the wise thing to do, but it would get closed anyways.
        close(pipe_fds[1]);

        //Now that we've let Pops know that we're alive...
        exit(EXIT_SUCCESS);
        }

     else if (cpid > 0) {
        char buf[BUFLEN] = {};
        int bytes_read = 0;

        //close *our* write end of the pipe. Important!
        //Comment this out and watch your program hang.
        //Again, check out `man 7 pipe`.
        close(pipe_fds[1]);

        //read data from pipe until we reach EOF
        while ((bytes_read = read(pipe_fds[0], buf, BUFLEN - 1)) > 0) {
            //null terminate our string.
            //(We could use snprintf instead...)
            buf[bytes_read] = '\0';

            //You can comment this out to prove to yourself that
            //we're the one printing the child's message.
            printf("%s", buf);
            }

        //close read end of pipe
        close(pipe_fds[0]);

        //wait for our child to terminate.
        wait(NULL);

        printf("I proudly parented 1 child.\n");
        }

     return 0;
     }

正如您所见,我刚刚提供了一个关于完成作业需要了解的两个概念的小教程。我需要一些睡眠,所以今晚我会把它留在那里。

阅读并试验这些示例!评论中的注释可以帮助您学习。