c - 如何为 n 个子进程实现 n 个管道

标签 c pipe child-process

我有这段代码应该创建 n 个子节点和 n 个管道(n 作为主参数给出),我想做的是使用方便的管道通过读取将 char* 发送到指定的子节点/编写系统调用但它实际上并没有工作(我是系统编程的新手)

这是主要的

int main(int argc, char const *argv[])
{
int tmp,np;
int tube[MAX_PROCESS][2], i;
pid_t pid[MAX_PROCESS];
char *chaine;


if(argc != 2){
    perror("Error : nombre d'arguments est invalide\n");
    exit(EXIT_FAILURE);
}

tmp = atoi(argv[1]);

if(tmp > 10){
    fprintf(stderr,"Erreur : nombre de processus fils doit étre inférieure a %d", MAX_PROCESS);
    exit(EXIT_FAILURE);
}
for(i=0;i<tmp;i++){
    if(pipe(tube[i]) == -1){
        perror("Erreur lors du création du tube");
        exit(EXIT_FAILURE);
    }
}
printf("fermeture des tubes de lecture dans le pere\n");

for(i=0; i < tmp; i++){

            if(close(tube[i][TUBE_LECTURE]) == -1){
                fprintf(stderr,"Erreur lors la fermeture de tube de lecture %d\n",i);
                exit(EXIT_FAILURE);
            }else
                printf("tube %d fermé\n", i);
}


printf("lecture a partir du clavier d'une chaine et du numéro du fils voulu : \n");

chaine = (char*) malloc(sizeof(char));

if(scanf("%s %d", chaine, &np) != 2){
    perror("Erreur de lecture de la chaine ou du numéro du processus fils\n");
    exit(EXIT_FAILURE);
}


printf("création des fils...\n");

for(i=0; i<tmp; i++){
    if((pid[i] = fork()) == -1){
        perror("Erreur lors du création des fils");
        exit(EXIT_FAILURE);
    }
}


printf("Initialisation fonction 'fils'\n");
for(i=0;i<tmp;i++) {
    if(pid[i] == 0)
        fils(np,tmp,tube);
}

printf("ecriture dans le tube\n");

if(write(tube[np][TUBE_ECRITURE],chaine,sizeof(chaine)) == -1){
    perror("Erreur ecriture dans le tube\n");
    exit(EXIT_FAILURE);
}

/*fermeture des tubes d'écriture*/

for(i=0; i< tmp; i++){
    if(close(tube[i][TUBE_ECRITURE]) == -1){
        perror("Erreur lors la fermeture de tube de l'écriture\n");
        exit(EXIT_FAILURE);
    }
}

/*attente des fils*/

for(i=0;i<tmp;i++){
    if(waitpid(pid[i],NULL, 0) == -1){
        fprintf(stderr,"Erreur lors de l'attente du fils %d",i);
        exit(EXIT_FAILURE);
    }
    else
        printf("le fils %d a terminé\n", i);
}

printf("tous les fils ont terminé\n");


return EXIT_SUCCESS;
}

它正在打印以下错误:

  fermeture des tubes de lecture dans le pere
  tube 0 fermé
  tube 1 fermé
  tube 2 fermé
  tube 3 fermé
  lecture a partir du clavier d'une chaine et du numéro du fils voulu : 
  yassine
  2
  création des fils...
  Initialisation fonction 'fils'
  ecriture dans le tube
  Initialisation fonction 'fils'
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Erreur lors de la lecture Bad file descriptor

最佳答案

你有很多概念上的错误。

  1. 在执行fork 之前,您不能关闭管道的读取端。这 child 继承 parent 的文件描述符的状态,你必须 fork 然后关闭管道的读取端在父进程

  2. 当你使用fork时,你必须为子进程和子进程编写代码 进程。你没有这样做,但不是在正确的地方。你做

    printf("création des fils...\n");
    
    for(i=0; i<tmp; i++){
        if((pid[i] = fork()) == -1){
            perror("Erreur lors du création des fils");
            exit(EXIT_FAILURE);
        }
    }
    

    在这里你正在为许多 child 创造道路, children 也在执行 fork 在接下来的迭代中,你最终不会得到几个 child ,而是得到一个 整个 child 军队。根据 tmp 的大小,您可能会消耗所有 fork 允许进程。在你的情况下,只有 parent 应该做 fork (请参阅下面我的代码)。

  3. 这段代码:

    chaine = (char*) malloc(sizeof(char));
    
    if(scanf("%s %d", chaine, &np) != 2){
        perror("Erreur de lecture de la chaine ou du numéro du processus fils\n");
        exit(EXIT_FAILURE);
    }
    

    should not cast malloc在这里,您正在为 one 分配空间 字符,为什么还要费心为单个字符动态分配内存。 然后在 scanf 中使用来读取字符串。这会溢出缓冲区,因为 字符串以 '\0' 结尾,即使对于长度为 1 的字符串,您也需要 2 空格。

  4. 我不太明白np是什么意思,但后来你明白了

    if(write(tube[np][TUBE_ECRITURE],chaine,sizeof(chaine)) == -1){
    

    但你永远不会检查 np 是否在 [0-MAX_PROCESS] 范围内,你可能会访问 管道数组越界。

  5. 这里

    if(write(tube[np][TUBE_ECRITURE],chaine,sizeof(chaine)) == -1){
    

    sizeof(chaine) 给出了指针的大小,但是如果试图发送一个字符串, 你应该写 strlen(chaine)+1 字节,+1 用于 \0-终止 byte 否则管道另一边的 child 不知道有多少 它应该为字符串读取的字节数。

  6. perror 只应在函数返回错误值并设置时使用 错误号。代码开头,如果argc != 2,那么这个不设置 errno 为任何值,使用 perror 将打印出误导性的错误消息。你 应该使用 fprintf(stderr, "... 代替。

所以这是一个版本(没有fils功能,因为我不知道它是什么 确实)向您展示了如何fork 并通过管道发送数据。

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

#define MAX_PROCESS 5

int child_process(int id, int tube[2], int np)
{
    int ret = 0;
    char buffer[100] = {0};
    printf(" Child %d, attempt to read 100 characters from parent. np is: %d\n", id, np);

    // closing writing end
    close(tube[1]);

    ssize_t size = read(tube[0], buffer, sizeof buffer);

    if(size <= 0)
    {
        printf(" Child %d, could not read from parent\n", id);
        ret = 1;
    } else {
        // making sure to \0-terminate string
        if(buffer[size] != 0)
            buffer[size - ( size == sizeof(buffer) ? 1 : 0)] = 0;
        printf(" Child %d: parent sent '%s'\n", id, buffer);
    }

    // closing reading end
    close(tube[0]);

    return ret;
}

int main(int argc, char **argv)
{
    int tube[MAX_PROCESS][2], i;
    pid_t pid[MAX_PROCESS];

    if(argc != 2){
        fprintf(stderr, "Error : nombre d'arguments est invalide\n");
        exit(EXIT_FAILURE);
    }


    int noc = atoi(argv[1]);

    if(noc <= 0 || noc > MAX_PROCESS)
    {
        fprintf(stderr, "Erreur : nombre de processus fils doit étre inférieure a %d", MAX_PROCESS);
        exit(EXIT_FAILURE);
    }

    printf("lecture a partir du clavier d'une chaine et du numéro du fils voulu : \n");

    char chaine[100];
    int np;

    if(scanf("%99s %d", chaine, &np) != 2)
    {
        fprintf(stderr, "Erreur de lecture de la chaine ou du numéro du processus fils\n");
        exit(EXIT_FAILURE);
    }

    if(np < 0 || np >= MAX_PROCESS)
    {
        fprintf(stderr, "Error: np must be in range [0 - %d]\n", MAX_PROCESS-1);
        exit(EXIT_FAILURE);
    }

    printf("création des fils...\n");


    for(i = 0; i < noc; ++i)
    {
        if(pipe(tube[i]) == -1)
        {
            perror("pipe");
            exit(EXIT_FAILURE);
        }

        pid[i] = fork();

        if(pid[i] == -1)
        {
            perror("fork");
            exit(EXIT_FAILURE);
        }

        if(pid[i] == 0)
        {
            // CHILD PROC
            exit(child_process(i, tube[i], np));
        }

        // PARENT PROC
        // closing reading end
        close(tube[i][0]);
    }

    // parent sends data to children
    for(i = 0; i < noc; ++i)
    {
        size_t len = strlen(chaine) + 1;
        if(write(tube[i][1], chaine, len) != len)
            fprintf(stderr, "Parent could not send the whole string to the child %d\n", i);

        // closing writing pipe
        close(tube[i][1]);
    }

    for(i = 0; i < noc; ++i)
    {
        if(waitpid(pid[i],NULL, 0) == -1){
            fprintf(stderr,"Erreur lors de l'attente du fils %d\n",i);
            exit(EXIT_FAILURE);
        }
        else
            printf("le fils %d a terminé\n", i);
    }


    exit(EXIT_SUCCESS);
}

有这样的输出:

$ ./a 5
lecture a partir du clavier d'une chaine et du numéro du fils voulu : 
HelloWorld 3
création des fils...
 Child 0, attempt to read 100 characters from parent. np is: 3
 Child 1, attempt to read 100 characters from parent. np is: 3
 Child 2, attempt to read 100 characters from parent. np is: 3
 Child 0: parent sent 'HelloWorld'
 Child 2: parent sent 'HelloWorld'
 Child 3, attempt to read 100 characters from parent. np is: 3
 Child 1: parent sent 'HelloWorld'
 Child 3: parent sent 'HelloWorld'
 Child 4, attempt to read 100 characters from parent. np is: 3
 Child 4: parent sent 'HelloWorld'
le fils 0 a terminé
le fils 1 a terminé
le fils 2 a terminé
le fils 3 a terminé
le fils 4 a terminé

关于c - 如何为 n 个子进程实现 n 个管道,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49161927/

相关文章:

node.js - Node 子进程执行命令失败,错误代码 1

c - 以 '\' 开头并后跟数字(例如 '\234')的字符是什么意思?

c - 在 Linux 中查找命令的内置和可执行文件的路径

c - 为什么我的 C 代码中的 pipe() 不断返回 -1

c - 另一个 Linux 命令输出(管道)作为我的 C 程序的输入

node.js - 运行 grunt 时出现错误 : spawn ./node_modules/.bin/grunt ENOENT

javascript - 在 Cloud Foundry Node.js 上运行子进程

java - 将 Java float 转换为 C

c - 我应该读/写多少字节到一个套接字?

c - 如何读取子进程的输出?