I thought the wait(4) instruction would force the parent process to wait for it's children to finish but does not, actually the process "hijo2" launches first, the "padre" second and "hijo1" third
int variable = 6;
if (fork() == 0){
variable = variable -3;
printf("\nLa variable del proceso hijo1 contiene %d\n", variable);
} else if (fork()==0){
variable = variable -3;
printf("\nLa variable del proceso hijo2 contiene %d\n", variable);
} else {
wait(2);//para esperar a que terminen los hijos
variable = variable +5;
printf("\nLa variable del proceso padre contiene %d\n", variable);
}
exit(0);
wait waits for one child to terminate. You need to call it twice.
Related
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.
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.
Thank you for reading this, I appreciate a lot!
I have this part of code:
for(i=0;i<n;i++)
{
printf("dopo %d sec ricevuto kill\n",20-sleep(20));
kill( pidFiglio[i],SIGKILL);
}
for (i=0 ; i<n ; i++)
{
//attesa della terminazione di un processo figlio
pidDaWait = wait( & status );
//(...)
but i can't understand why the father process is able to wait his sons, after he killed them!
The kill function returns 0 so it works, but the father is able to wait "his sons" after.
I know that it's a stupid answer, but I'm absolutely new in multiprogramming.
#include <stdio.h>
#include <stdlib.h> //per la exit()
#include <unistd.h> //per la fork()
#include <sys/types.h> //per la wait()
#include <sys/wait.h> //per la wait()
#include <signal.h> //per la signal()
int contSigusr1;
void trapSIGUSR1(int nsignal);
int main( int argc , char* argv[] )
{
int i;
int n;
pid_t pidFiglio[10];
pid_t pidDaWait;
int status;
contSigusr1=0;
signal ( SIGUSR1, trapSIGUSR1 );
printf("argc = %d\n", argc);
if ( argc < 3 )
{
printf("Sintassi errata!\n");
printf("il programma termina con errore\n");
exit(1);
}
n = atoi( argv[1] );
for (i=0; i<n; i++)
{
pidFiglio[i] = fork();
if ( pidFiglio[i] == 0 )
{
printf("Figlio - getpid = %d\n", getpid());
printf("Figlio - getppid = %d\n", getppid());
printf("(%d)%s\n",getpid(),argv[2+i]);
sleep(i*5);
kill( getppid() , SIGUSR1);
sleep(i+1*5);
printf("Figlio - termina correttamente\n");
exit(0);
}
}
printf("getpid = %d\n", getpid());
printf("getppid = %d\n",getppid());
for(i=0;i<n;i++)
{
printf("dopo %d sec ricevuto kill\n",20-sleep(20));
kill( pidFiglio[i],SIGKILL);
}
for (i=0 ; i<n ; i++)
{
pidDaWait = wait( & status );
printf("status = %d\n", status);
printf("status di (%d) con WEXITSTATUS = %d\n",
pidDaWait,
WEXITSTATUS( status));
if ( WIFSIGNALED (status) )
printf("il processo figlio (%d) e` terminato tramite un segnale\n",pidDaWait);
else
printf("il processo figlio (%d) e` terminato normalmente\n",pidDaWait);
}
printf("il padre termina dopo la terminazione del processo figlio con pid = %d\n",pidDaWait );
exit(0);
}
void trapSIGUSR1(int nsignal)
{
contSigusr1= contSigusr1 +1;
printf("riceived %d SIGUSR1 = %d\n",nsignal,contSigusr1);
}
Just don't pay attention to the italian words :D
Thank you in advance,
Have a good day!
Childs still exist, but are now zombies.
Childs may terminate their execution, but the task_struct still exists in kernel. The task_struct in kernel holds the return status information from the child (and some other info). The zombie task_struct exists only so that the parent process may get the child return status (via wait(&status) + WEXITSTATUS(status)) and other information about the child, so that parent code may be consistent.
Sending SIGKILL to children or terminating all children using exit() call (like in wikipedia) does not matter - the result is that the child process becomes a zombie. After the parent calls wait and that wait services that child, it's task_struct from kernel get's freed and the status information get's returned to the parent, so he can handle it.
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()
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).