1

I have this code that is supposedly creating n childs and n pipes (n given as an argument to the main) and what i am trying to do is to send a char* to a specified child using the convenient pipe throught read/write system calls and it's not actually working (i'm a newbie in system programming)

This is the main

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;
}

it's printing the following error :

  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
yassine yousfi
  • 79
  • 2
  • 11
  • When you create a fork, you have to distinguish between parent and child, you are not doing that. – Pablo Mar 07 '18 at 22:11
  • `chaine = (char*) malloc(sizeof(char));` you are allocating space for a single `char`. Why do you even bother to allocate for just one byte? And it's not enough for a string, because strings must be 0-terminated – Pablo Mar 07 '18 at 22:13

1 Answers1

0

You have many conceptual errors.

  1. You cannot close the reading end of the pipes before you do the fork. The children inherit the status of the file descriptors of the parents, you have to fork and then close the reading end of the pipe in the parent process

  2. When you use fork, you have to write code for the child process and for the parent process. You are not doing that, but not at the correct place. You do

    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);
        }
    }
    

    here you are creating way to many children, the children and also executing fork in the next iterations, you don't end up with a few children, but with a whole army of children. Depending on how large tmp is, you might consume all fork allowed for a process. Only the parent should do the fork in your case (see my code below).

  3. This code:

    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);
    }
    

    You should not cast malloc and here you are allocating space for one charcter, why even bother to dynamically allocate memory for a single character. Then you use in scanf for reading a string. This overflows the buffer, because a string is '\0'-terminated and even for a string of length 1 you need 2 spaces.

  4. I don't really understand what's the meaning of np, but later on you do

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

    but you never check if np is in the range [0-MAX_PROCESS], you might access the pipes array out of bounds.

  5. Here

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

    sizeof(chaine) gives the size of pointer, but if are trying to send a string, you should write strlen(chaine)+1 bytes, the +1 is for the \0-terminating byte otherwise the child on the other side of the pipe cannot know how many bytes it should read for the string.

  6. perror should only be used when a function returns an error value and sets errno. At the beginning of the code, if argc != 2, then this does not set errno to any value, using perror will print a missleading error message. You should use fprintf(stderr, "... instead.

So this is a version (without the fils function, because I don't know what it does) that shows you how to fork and send data through the pipes.

#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);
}

Which has this output:

$ ./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é
Pablo
  • 13,271
  • 4
  • 39
  • 59
  • thank you, you've helped me alot, i didn't actually give it a chance to understand the basics, as for the np, we're supposed to send the string to a particular child (wich number is np), wich i didn't mention in the question, i defined tmp because i thought that every child have access to all pipes and should deal with them as a whole – yassine yousfi Mar 08 '18 at 14:04
  • You need a pipe per child, otherwise the parent wouldn't know which child is talking and the children would have to synchronize in order to write into the pipe. – Pablo Mar 08 '18 at 14:40
  • yeah, after studying the basics and putting some energy and time to it, i understood how it should be done, and i did it, thank you – yassine yousfi Mar 08 '18 at 23:00