C了解从管阻塞,直到孩子被终止 [英] C Read from pipe blocks until child is terminated

查看:93
本文介绍了C了解从管阻塞,直到孩子被终止的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

父进程创建n儿童EXEC每一个替换其本身。有通过管道数组父母和exec之间的通信( INT pipefd [N] [2];

EXEC 写这些命令管道:

 字符味精[50];
sprintf的(味精,\\ tsent从PID:%D,PI =%F,GETPID(),PI);
的printf(%S \\ n,味精);
写(I1,味精,strlen的(MSG)+1);

和家长与这些内容如下:

 为(i = 0; I< N;我++){
   关闭(pipefd [I] [1]); //关闭管道的写入结束在父   读(pipefd [I] [0],缓冲液,的sizeof(缓冲液));
   的printf(\\ n-C- \\ n);   如果(缓冲[0] =='\\ t'){
     的printf(%S \\ n,缓冲区);
   }
   诠释J;
   为(J = 0; J&小于100; J ++){
      缓冲[J] ='\\ n';
   }
   关闭(pipefd [I] [0]);
}

现在的问题是,孩子被终止的之后读变得畅通和打印缓冲区。
我想要做的就是打印缓冲区EXEC写入管道之后。

下面是所有code:

父文件:

 的#include<&signal.h中GT;
#包括LT&;&stdio.h中GT;
#包括LT&; SYS / types.h中>
#包括LT&;&unistd.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&; SYS / time.h中>
#包括LT&;&string.h中GT;#定义N 5
将为pid_t * PID;
INT pipefd [N] [2];INT标志= 0;
INT count_ctrl_c = 0;
无效signal_handler(INT SIG){
    信号(SIG,SIG_IGN);
    的printf(\\ n);    标志= 1;
    信号(SIGINT,signal_handler);
}INT主(INT ARGC,CHAR *的argv []){
    INT I;
    对于(i = 0; I< N;我++){
        管(pipefd [I]);
    }    INT parent_pid = GETPID();
    PID =(*将为pid_t)的malloc(N * sizeof的(将为pid_t));    对于(i = 0; I< N;我++){
        PID [I] =叉();
        如果(PID [I] == 0)//父进程将继续循环
        {            焦B〔50];
            sprintf的(B,%D,我+ 1);            焦炭I0 [50];
            的sprintf(I0,%d个,pipefd [I] [0]);            焦炭I1 [50];
            的sprintf(I1,%d个,pipefd [I] [1]);            焦炭PAR_ID [50];
            sprintf的(PAR_ID,%D,parent_pid);            EXECL(***的/路径/要/ EXEC /计算***,B,I0,I1,PAR_ID,NULL);
        }
    }    如果(parent_pid == GETPID()){
        信号(SIGINT,signal_handler);
        而(1){
            如果(标志){                的printf(\\ n-A- \\ n);
                炭缓冲器[100];
                INT I;
                对于(i = 0; I< N;我++){
                    // Apostellei到硕码SIGUSR2本身OLA TA paidia土特产品
                    杀死(PID [I],SIGUSR2);
                }                的printf(\\ n-B- \\ n);
                对于(i = 0; I< N;我++){
                    关闭(pipefd [I] [1]); //关闭管道的写入结束在父                    读(pipefd [I] [0],缓冲液,的sizeof(缓冲液));
                    的printf(\\ n-C- \\ n);
                    如果(缓冲[0] =='\\ t'){
                        的printf(%S \\ n,缓冲区);
                    }
                    诠释J;
                    为(J = 0; J&小于100; J ++){
                        缓冲[J] ='\\ n';
                    }
                    关闭(pipefd [I] [0]);
                }
                //出口(0);
                的printf(读完\\ n);                标志= 0;
                count_ctrl_c ++;
                如果(count_ctrl_c == 2){
                    出口(0);
                }
            }        }
    }
}

calculate.c

 的#include<&signal.h中GT;
#包括LT&;&stdio.h中GT;
#包括LT&; SYS / types.h中>
#包括LT&;&unistd.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&; SYS / time.h中>
#包括LT&;&string.h中GT;#定义N 5INT I0,I1,parent_pid;INT标志= 0;
INT time_to_term = 0;
双PI;无效signal_handler2(INT SIG);
无效signal_handler(INT SIG);无效signal_handler2(INT SIG){
    信号(SIG,SIG_IGN);
    信号(SIGALRM,SIG_IGN);
    标志= 1;
    信号(SIGUSR2,signal_handler2);
    信号(SIGALRM,signal_handler);
}无效signal_handler(INT SIG){
    信号(SIG,SIG_IGN);
    将为pid_t PID = GETPID();
    的printf(时间:%D,PID:%D,PI:%1.10f \\ n,time_to_term,PID,PI);
    出口(0);
}INT主(INT ARGC,CHAR *的argv []){
    INT PID;
    信号(SIGINT,SIG_IGN);
    信号(SIGUSR2,signal_handler2);
    信号(SIGALRM,signal_handler);    time_to_term =的atoi(argv的[0]);
    报警(time_to_term);    I0 =的atoi(ARGV [1]);
    I1 =与atoi(argv的[2]);
    parent_pid =的atoi(argv的[3]);    双穆尔= 1.0;
    双杆= 2.0;
    PI = 3.0;    而(1){
        PI =圆周率+(MUL *(4.0 /(参数*(参数+ 1.0)*(参数+ 2.0))));
        MUL = MUL *(-1.0);
        面值+ = 2;        睡眠(1);         如果(标志){
            信号(SIGALRM,SIG_IGN);
            关闭(I0);            味精的char [50];
            sprintf的(味精,\\ tsent从PID:%D,PI =%F,GETPID(),PI);
             的printf(%S \\ n,味精);
            写(I1,味精,strlen的(MSG)+1);            关闭(I1);
            标志= 0;            信号(SIGALRM,signal_handler);
            //出口(0);
        }
    }}


解决方案

恕我直言,你的设计是不是真的好,因为所有子进程继承您创建的所有管道,这是系统资源的浪费。做正确的做法是:

在父进程:


  1. DUP FD的#0和#1〜preserve由父进程以后使用;使用的fcntl F_DUPFD_CLOEXEC 对这些新的FD对prevent继承上 EXEC


  2. 关闭 FD#0


  3. 关闭 FD#1


  4. 创建管道


  5. 作为所述上面

    的管的读出FD的

    prevent继承


  6. dup2 写管道FD使它的fd#1; 关闭原来写的fd


  7. &安培; EXEC 子进程


  8. 重复步骤3至7所有必要的儿童


  9. dup2 原FD的#0和#1回#0,#1,恢复的printf / SCAF 功能


  10. 使用选择如果您期望在#0任何输入轮询所有管道的读FD的和可能#0


如果需要双向通信,则在步骤4创建两个管道与适当的调整,以所描述的过程,并重复步骤2到7来创建儿童

在子进程(以后 EXEC

做对所有所需的处理。写或者使用FD#1或printf或任何父。
子进程可以始终获得其父 PID getppid()

Parent process creates N children each one replaces itself with exec. There is a communication between parent and exec through an array of pipes (int pipefd[N][2];)

The exec writes to the pipe with these commands:

char msg[50];
sprintf( msg, "\tsent from pid: %d, pi= %f", getpid(), pi);
printf("%s\n",msg);
write(i1, msg, strlen(msg)+1);

and the parent reads with these:

for (i=0;i<N;i++) {
   close(pipefd[i][1]);  // close the write end of the pipe in the parent

   read(pipefd[i][0], buffer, sizeof(buffer));
   printf("\n-C-\n");

   if (buffer[0] == '\t'){
     printf("%s\n",buffer);
   }
   int j;
   for (j=0; j<100; j++) {
      buffer[j]='\n';
   }
   close(pipefd[i][0]);
}

Now the problem is that only after the child is terminated the read gets unblocked and prints the buffer. What I want to do is print the buffer immediately after the exec writes to the pipe.

Below is the all the code:

Parent File:

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

#define N 5
pid_t *pid;
int pipefd[N][2];

int flag = 0;
int count_ctrl_c = 0;
void signal_handler(int sig){
    signal(sig, SIG_IGN);
    printf("\n");

    flag = 1;
    signal(SIGINT, signal_handler);
}

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


    int i;
    for (i = 0; i < N; i++) {
        pipe(pipefd[i]);
    }

    int parent_pid = getpid();
    pid= (pid_t *)malloc(N * sizeof(pid_t));

    for (i = 0; i < N; i++) {
        pid[i] = fork();
        if (pid[i] == 0) //The parent process will keep looping
        {

            char b[50];
            sprintf( b, "%d", i+1);

            char i0[50];
            sprintf( i0, "%d", pipefd[i][0]);

            char i1[50];
            sprintf( i1, "%d", pipefd[i][1]);

            char par_id[50];
            sprintf( par_id, "%d", parent_pid);

            execl("***the/path/to/exec/calculate***", b,i0,i1,par_id,NULL);
        }
    }

    if (parent_pid == getpid()) {
        signal(SIGINT, signal_handler);


        while(1){
            if (flag){

                printf("\n-A-\n");
                char buffer[100];
                int i;
                for (i=0;i<N;i++) {
                    // Apostellei to shma SIGUSR2 se ola ta paidia tou
                    kill(pid[i], SIGUSR2);
                }

                printf("\n-B-\n");
                for (i=0;i<N;i++) {
                    close(pipefd[i][1]);  // close the write end of the pipe in the parent

                    read(pipefd[i][0], buffer, sizeof(buffer));
                    printf("\n-C-\n");
                    if (buffer[0] == '\t'){
                        printf("%s\n",buffer);
                    }
                    int j;
                    for (j=0; j<100; j++) {
                        buffer[j]='\n';
                    }
                    close(pipefd[i][0]);
                }
                //exit(0);
                printf("finished reading\n");

                flag = 0;
                count_ctrl_c++;
                if (count_ctrl_c == 2) {
                    exit(0);
                }
            }

        }
    }
}

calculate.c

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

#define N 5

int i0,i1,parent_pid;

int flag = 0;
int time_to_term = 0;
double pi;

void signal_handler2(int sig);
void signal_handler(int sig);

void signal_handler2(int sig){
    signal(sig, SIG_IGN);
    signal(SIGALRM, SIG_IGN);
    flag = 1;
    signal(SIGUSR2, signal_handler2);
    signal(SIGALRM, signal_handler);
}

void signal_handler(int sig){
    signal(sig, SIG_IGN);
    pid_t pid = getpid();
    printf("time: %d, pid: %d, pi: %1.10f\n", time_to_term, pid, pi);
    exit(0);
}

int main(int argc, char *argv[]) {
    int pid;
    signal(SIGINT, SIG_IGN);
    signal(SIGUSR2, signal_handler2);
    signal(SIGALRM, signal_handler);

    time_to_term = atoi(argv[0]);   
    alarm(time_to_term);

    i0 = atoi(argv[1]);
    i1 = atoi(argv[2]);
    parent_pid = atoi(argv[3]);

    double mul = 1.0;
    double par = 2.0;
    pi = 3.0;

    while(1){


        pi = pi + (mul * (4.0 / (par * (par + 1.0) * (par + 2.0))));
        mul = mul * (-1.0);
        par += 2;

        sleep(1);

         if (flag) {
            signal(SIGALRM, SIG_IGN);
            close(i0);

            char msg[50];
            sprintf( msg, "\tsent from pid: %d, pi= %f", getpid(), pi);
             printf("%s\n",msg);
            write(i1, msg, strlen(msg)+1);

            close(i1);
            flag = 0;

            signal(SIGALRM, signal_handler);
            //exit(0);


        }
    }

}

解决方案

IMHO, your design is not really good as all child processes inherit all pipes you created and this is a waste of system resources. The right thing to do would be:

In the parent process:

  1. dup fd's #0 and #1 to preserve for later use by the parent process; use fcntl with F_DUPFD_CLOEXEC on these new fd's to prevent inheritance on exec

  2. close fd #0

  3. close fd #1

  4. create a pipe

  5. prevent inheritance of the read fd of the pipe as said above

  6. dup2 write fd of the pipe to make it fd #1; close the original write fd

  7. fork & exec the child process

  8. repeat steps 3 through 7 for all necessary children

  9. dup2 stored duplicates of original fd's #0 and #1 back to #0 and #1 to restore the printf/scaf functionality

  10. use select to poll read fd's of all pipes and possibly #0 if you expect any input on #0

If two-way communication is required then at step 4 create two pipes with appropriate adjustments to the described procedure and repeat steps 2 through 7 to create children.

In the child process (after exec)

Do all processing as required. Write to the parent either using fd #1 or printf or whatever. Child process may always obtain its parent PID with getppid()

这篇关于C了解从管阻塞,直到孩子被终止的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆