how to emplement n pipes for n child processes - c

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

You have many conceptual errors.
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
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).
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.
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.
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.
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é

Related

How can I have a parent and child processes modify and read the same variable?

I have to do a project in C using child processes and pipe communication , but I cannot get it to work properly.
The project consists on a menu of operations to do in a linked list, we can load a new node to the list, delete one node, print the info of one node, print the info of all nodes etc...
void menu(){
printf("Introduzca una de las siguientes opciones: \n\n");
printf("1. load \n");
printf("2. delete \n");
printf("3. info \n");
printf("4. infoall \n");
printf("5. help \n");
printf("6. save_collection \n");
printf("7. load_collection \n");
printf("8. add_op_id \n");
printf("0. exit \n");
printf("\n");
printf("Si introduce CTRL+D en este menú, el programa terminará de forma controlada.\n");
printf("\n");
}
What I need to achieve is that whenever I load a new node into the list I create a child process which is the one who will execute the operations on the node, the parent process will only recieve the option and communicate it to the child process through a pipe so the child can read and call that function/option.
My problem is that, I call fork() in case: load is called, and then if the child is created fine I load the node into the list, however this list is a "copy" of the list of the parent process so if I load another node it will be loaded into a new copy of the list of the parent, and overall if the parent wants to print for example the information of the nodes of its list it will appear empty as the list on which we have loaded the nodes is not the "original" one.
I add the code of the main program (the code is downgraded to try at first with one basic operation):
int main(int argc, char *arg_argv[])
{
int error=0;
signal_inicio();
menu();
int fd[2];
if(pipe(fd)){
perror("pipe(...)");
exit(1);
}
char opcion[]= "infoall";
//opcion[strlen(opcion)+1]='\0';
int salir = 1;
while(salir==1){
printf("\n");
printf("Introduzca una opción válida: %d", getpid());
long option = get_number(&error);
if(error != 0){
libero();
printf("ERROR: Opción no válida\n");
}
switch(option){
case 0:
puts("---Ha seleccionado exit---");
puts("---TERMINAMOS---");
printf("PID: %d\n", getpid());
vaciarLista(&lista);
libero();
salir = 0;
//exit(0);
break;
case 1:
//int status;
puts("---Ha seleccionado load---");
printf("\n Introduzca un nombre de archivo\n");
char *archivo = get_string(&error);
if(error!=0){
libero();
printf("Introduzca un nombre de archivo valido.\n");
}else{
pid_t pid;
pid = fork();
if (pid==-1){
//No se ha creado bien el hijo
perror("fork()");
//exit(1);
}else if(pid == 0){
//El hijo se ha creado bien, creo la pipe fd
//Cargo el archivo con el pid y los descriptores de fichero.
load(&lista, archivo, getpid(), fd ,&error);
printf("El f[0] del PADRE es: %d: \n", fd[0]);
child(&lista);
break;
}else{
printf("Soy el padre y escribo en el pipe: %d %s\n", getpid(),opcion);
}
}
break;
case 2:
puts("---Ha seleccionado delete---");
printf("\n Introduzca el identificador del nodo que quiere borrar: \n");
long option3 = get_number(&error);
if(error!=0){
libero();
printf("Oh oh, an error happened!\n");
}
printf("The second number is: %ld\n",option3);
delete(&lista, option3, &error);
wait(NULL);
break;
case 3:
puts("---Ha seleccionado info---");
break;
case 4:
puts("---Ha seleccionado infoall---");
write(fd[1],opcion,(strlen(opcion)+1));
printf("PADRE\n");
infolista_all(&lista);
//close(fd[1]);
break;
case 5:
puts("---Ha seleccionado help---");
menu();
break;
default:
break;
}
}
vaciarLista(&lista);
libero();
return 0;
}
Child function:
void child(struct lista *lista){
char buff[50];
printf("--1--\n");
printf("El fd[0] del HIJO es: %d: \n", lista->head->fd[0]);
while(1){
printf("--2--\n");
int nbytes = read(lista->head->fd[0],buff, sizeof(buff));
printf("--3--\n");
if(nbytes>0){
printf("--4--\n");
printf("Bytes: %d \n", nbytes);
printf("Recibido: %s \n",buff);
/* if(strcmp(buff,"infoall")==0){
infolista_all(lista);
}else{
}*/
//break;
}else{
printf("No hemos leido nada \n");
}
break;
//exit(0);
}
}
You didn't post the source to load(), but if it is merely a book-keeping sort of thing:
load(&lista, archivo, 0, fd ,&error);
pid = fork();
if (pid==-1){
//No se ha creado bien el hijo
perror("fork()");
//exit(1);
}else if(pid == 0){
list.pid = getpid();
//El hijo se ha creado bien, creo la pipe fd
//Cargo el archivo con el pid y los descriptores de fichero.
printf("El f[0] del PADRE es: %d: \n", fd[0]);
child(&lista);
break;
That is, move the generic construction of the data object up into the parent; and edit the child-specific parts in the child. Each has their own copy, so won't really interfere with each other.

I try using signals and the pause() function in c in my college homework but to no avail

The following program is supposed to do this:
The main process should create a child process,which I will refer to as main child from now on for convenience,then wait for a SIGUSR2 signal, then send a SIGUSR1 signal to his child and grandchildren, then wait for his child and finally end.
The main child should do the following 4 times: create a child and wait for SIGUSR2. After that the process should send a SIGUSR2 to his father,then wait for SIGUSR1, then wait for his children to end and finally end.
The main child's children should print Proceso "PID" listo,then send a SIGUSR2 to the main child,then wait for SIGUSR1,then print Señal capturada and finally end.
However it just prints one PID and then it never ends unless I use CTRL^C.I've tried changing the order of the pause() fucntions but to no avail. Also this is homework for college and they said we can't use semaphores yet.
If you know Spanish here are the instructions:
• El proceso padre generará un proceso hijo, que será el proceso gestor.
• El proceso gestor creará N_PROC procesos hijos (los participantes en la competición) en un
bucle, esperando tras crear cada proceso a que éste le notifique que está preparado
enviándole la señal SIGUSR2 .
• Cada participante en la carrera, una vez activo y con la señal armada, imprimirá un mensaje
y avisará al gestor mediante la señal SIGUSR2 .
• El proceso gestor, cuando haya creado los N_PROC procesos hijos y éstos estén listos para la
competición, avisará al proceso padre de que está todo listo enviándole la señal SIGUSR2 .
• El proceso padre mandará al grupo entero de procesos la señal
de la competición).
• Cuando los participantes en la carrera reciban la señal
ya han capturado la señal, y terminarán.
• Cuando el proceso gestor reciba SIGUSR1 , terminará su ejecución sin dejar hijos huérfanos.
• El proceso padre esperará a que el proceso gestor termine y acabará él también.
Thanks in advance.
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define N_PROC 4
void manejador_SIGUSR1(int sig) {
printf("Señal capturada\n");
exit(EXIT_SUCCESS);
}
void manejador_SIGUSR2(int sig) {
}
int main(void){
int i,pid[N_PROC+1];
struct sigaction act;
sigemptyset(&(act.sa_mask));
act.sa_flags = 0;
/* Se arma la señal SIGUSR1. */
act.sa_handler = manejador_SIGUSR1;
if (sigaction(SIGUSR1, &act, NULL) < 0) {
perror("sigaction");
exit(EXIT_FAILURE);
}
act.sa_handler = manejador_SIGUSR2;
if (sigaction(SIGUSR2, &act, NULL) < 0) {
perror("sigaction");
exit(EXIT_FAILURE);
}
if((pid[0] = fork()) == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if(pid[0] == 0) {
for(i=0;i<N_PROC;i++){
if((pid[i+1] = fork()) == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if(pid[i+1]==0){
printf("Proceso %d listo\n",getpid());
kill(SIGUSR2,getppid());
pause();
}
else{
pause();
}
}
kill(SIGUSR2,getppid());
pause();
while(wait(NULL)>0);
exit(EXIT_SUCCESS);
}
pause();
kill(SIGUSR1,0);
while(wait(NULL)>0);
exit(EXIT_SUCCESS);
}
Short Answer
Your arguments to kill are swapped, as #Arkku noted in the comments. Your "main process" waits forever for a SIGUSR2 from its very first child, which it never receives.
Aside
Ha! An assignment about race conditions given in the language of races (la carrera, le señal de competición). That's great.
If I understand correctly, the desired flow is something like this:
+--> [competitor]
+--> [competitor]
[starter] --> [manager] -+--> [competitor]
+--> [competitor]
Starter creates manager
Manager gets competitors to the starting line
Create a competitor
Wait for the competitor to indicate it is ready (SIGUSR2)
Repeat for N_PROC competitors total
Manager tells the starter that competitors are ready (SIGUSR2)
Starter fires the starting pistol (SIGUSR1 to process group)
Competitors race!
Manager process terminates after reaping all competitors.
Starter terminates after reaping manager.
Several things can go wrong here. Notably, #PSkocik's comment is right: you should use sigwait or similar functions to avoid unintended races. Also, please don't use printf in a signal handler.

how can i create two child processes, each runs a different program in c

i'm trying to create 2 child processes through parent in c, each child process runs a different program?
how can i change this code to let each process run execution1() and execution2() ?
void execution1(char *argve[]);
void execution2(char *argve[]);
int main(int argc, char *argv[], char *argve[]) {
pid_t pid[2];
int i;
/* Creation du processus fils */
for(i=0; i < 2; ++i){
if((pid[i] = fork()) == -1) {
perror("Erreur lors de la creation du fils ");
exit(EXIT_FAILURE);
}
if(pid[i] == 0)
execution1(argve);
//execution2(argve); how can i let only the 2nd child run this line
}
/* Attente de la fin de l'execution du fils */
printf("Attente de la fin du fils...\n");
if(waitpid(pid, NULL, 0) == -1) {
perror("Erreur lors de l'attente de la fin du processus ");
exit(EXIT_FAILURE);
}
printf("C'est bon !\n");
return EXIT_SUCCESS;
}
Have you consider using i for that? If i is 0, then execute execution1, if i is 1, then execute execution2
for(i=0; i < 2; ++i)
{
if((pid[i] = fork()) == -1) {
perror("Erreur lors de la creation du fils ");
exit(EXIT_FAILURE);
}
if(pid[i] == 0)
{
if(i == 0)
execution1(argve);
else
execution2(argve);
// exiting child
exit(0);
}
}
// waiting
for(i=0; i < 2; ++i)
{
if(waitpid(pid[i], NULL, 0) == -1) {
perror("Erreur lors de l'attente de la fin du processus ");
exit(EXIT_FAILURE);
}
}
i'm trying to create 2 child processes through parent in c, each child process runs a different program?
For this you need to use fork-exec method.
You fork a child then launch new program with exec(), the entire memory image of child processes that called exec() will be replaced with that of new process created from the program you specified in exec()

SIGPIPE in bidirectional messaging with two pipes

Hi I've to develop this program that create 4 children and, sequentially, make 'em do a simple operation. The first will do the sum, the second the rest, the third the multiplication and the fourth the division. The father will write on the socket the string with the two number he wants his children to "calculate", and every children should read this string, extract the numbers and to the operations. Obviously, being two pipes, it's needed that the father writes every time the string, because of the read in the child. I don't really understand why at the second iteration, i receive a SIGPIPE on the write of the father. Can someone explain me why? I losed 3 days on debugging, but I didn't find anything. Thank you very much.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
/*
fd_0 padre escribe y hijo lee ==== padre cierra fd_0[0] y hijo cierra fd_0[1]
fd_1 hijo escribe y padre lee === padre cierra fd_1[1] y hijo cierra fd_1[0]
*/
int main (int argc, char * argv[]){
char * str = malloc(100*sizeof(char));//hijo
char readbuffer_h[150];
char * stringa = malloc(100*sizeof(char));//padre
char readbuffer_p[150];
int a,b;
int x,y;
int n = 4;
int i,status,nbytes, pipe_status;
int pid, ppid,yo,padre;
int fd_0[2], fd_1[2] ;
pipe_status=pipe(fd_0);
if(pipe_status==- 1) {
perror("Error creando la tuberia 0\n");
exit(EXIT_FAILURE);
}
pipe_status=pipe(fd_1);
if(pipe_status== -1) {
perror("Error creando la tuberia 1 \n");
exit(EXIT_FAILURE);
}
for(i=0; i< n; i++){
if ((pid=fork()) <0 ){
printf("Error al emplear fork\n");
exit(EXIT_FAILURE);
}
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
else if (pid ==0){// soy el hijo
yo = getpid();
padre = getppid();
printf("HIJO: %d, mi padre es: %d\n", yo, padre);
close(fd_0[1]);
close(fd_1[0]);
//TODO
nbytes = read(fd_0[0], readbuffer_h, sizeof(readbuffer_h));
sscanf(readbuffer_h, "%d,%d", &x, &y);
switch(i) {
case 0 :
//TODO
sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. La suma es %d", yo,x,y,(x+y));
break;
case 1 :
//TODO
sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. La resta es %d", yo,x,y,(x-y));
break;
case 2 :
//TODO
sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. El producto es %d", yo,x,y,(x*y));
break;
case 3 :
//TODO
sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. El cociente es %d", yo,x,y,(x/y));
break;
}
write(fd_1[1], str, strlen(str));
exit(EXIT_SUCCESS);
}
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
else{ //soy el padre
yo = getpid();
printf("PADRE:%d\n", yo);
a = 3; b = 4;
close(fd_0[0]);
close(fd_1[1]);
sprintf(stringa,"%d,%d",a,b);
printf("Stringa padre : %s\n", stringa);
fflush(stdout);
write(fd_0[1],stringa,strlen(stringa)); // questa write non va a buon fine
wait(&status);
read(fd_1[0], readbuffer_p, sizeof(readbuffer_p));
printf("%s\n",readbuffer_p);
fflush(stdout);
}
}
close(fd_0[0]);
close(fd_0[1]);
close(fd_1[0]);
close(fd_1[1]);
return 0;
}
You're getting yourself into trouble by trying to use the same pipes to communicate with each child.
You create two pipes at the beginning of the program. On the first iteration of the loop, the parent forks, and the child inherits all the parent's open file descriptors. The child closes the pipe ends it doesn't need, and the parent closes the pipe ends it doesn't need. Communication happens as intended (I imagine) -- all well and good so far.
But now consider the second iteration of the loop. You fork again, and the child again inherits the parent's open file descriptors. But now, the file descriptors the child wants to use were closed by the parent in the previous iteration of the loop. I'm a bit surprised that the child then gets an EPIPE instead of an EBADF when it tries to use those file descriptors, but I'm not at all surprised that its read attempt fails.
The cleanest thing to do would be to create a new pair of pipes for each child, instead of trying to reuse one set of pipes. If you want to make it work with just the one pair, then the parent process must avoid closing any of the pipe ends (though the child processes may close their copies, if you wish).

how to wait an exec finishes to write in pipe in C

I'd like to know how to wait for my exec finish to write in an fd before use it?
The problem is the fact that not all of my exec is wrote in the pipe.
So when I get the answer, not all of the exec is wrote.
here is the part of the code concerned :
switch(fork()){
case -1:
perror("fork");
case 0:
// redirection de l'entré standard
close(fd[0]);
dup2(fd[1], 1);
dup2(fd[1], 2);
close(fd[1]);
// éxécution de la commande courrante.
execvp(d->command[0], d->command);
perror("execvp");
default:
// gère les processus zombies.
if(wait(NULL) == -1){
perror("wait");
}
char buffer[550000] = {0};
unlink(d->pipe1);
unlink(d->tube2);
unlink(tube2);
//création du tube nommé pour le client.
if(mkfifo(tube2, 0644) != 0)
{
perror("mkfifo");
fprintf(stderr, "Impossible de créer le tube nommé.\n");
exit(EXIT_FAILURE);
}
// ouverture de ce même tube
if((d->entree_tube = open(tube2, O_WRONLY)) == -1)
{
perror("open");
fprintf(stderr, "Impossible d'ouvrir l'entrée du tube nommé.\n");
exit(EXIT_FAILURE);
}
close(fd[1]);
// lecture du résultat de la commande stocké dans fd[0]
while (read(fd[0], buffer, sizeof(buffer)) != 0)
{
//écriture du résultat dans l'entré du tube.
if(write(d->entree_tube, buffer, strlen(buffer)) == -1){
perror("write");
}
//réinitialisation du buffer stockant une partie du résultat de la commande.
memset (buffer, 0, sizeof(buffer));
}
// on regarde si il y a eu le mot clé "fin" pour alerter la client que la commande est terminé
// et on redonne la main à un autre client tentant de se connecter au démon.
}
Thanks for helping.
I tried not to wait as you asked, but it doesn't resolve anything, and I don't see how can I read again datas by an other loop of read.
You don't need an other loop of read - the read loop you already have is just fine. You only have to move the wait() call behind that read loop. That's what John Bollinger meant when he wrote: You do want to wait eventually, but not while you have any other responsibilities to the child.

Resources