Autor
|
Tema: Programacion en C (Leído 4,858 veces)
|
Andrea0000
Desconectado
Mensajes: 5
|
Buenas he hecho este codigo pero me queda por implementar una linea de codigo acerca de read que lea un caracter de entrada de la tuberia fd[0] y la verdad no se como hacerlo. Se encuentra en el for: /*Espera a la finalizacion de los procesos hijos*/ #define _POSIX_SOURCE #include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> #include <wait.h>
#define NUM_HIJOS 10//El numero de hijos debe ser tantos como numero de parametros haya #define NOMBREHIJO "./hijo"
void FinalizarProcesos();
void Manejador(int num);
pid_t pids[NUM_HIJOS]; int longitud_pid=0;//logitud del pid
int main(int argc, char *argv[]){ int fd[2];//Descriptores de la tuberia de comunicacion int i, j; //Para los bucles int pid; //PID de un proceso hijo int status; //terminacion proceso hijo /*Tratamiento de la linea de ordenes*/ if(argc < 2){// < 2 fprintf(stderr, "Error en el numero de argumentos\n"); exit(EXIT_FAILURE); } /*Tratamiento de la señal*/ if(signal(SIGINT, Manejador)== SIG_ERR){ fprintf(stderr, "Error en la manipulacion de la señal\n"); exit(EXIT_FAILURE); } /*?? Creacion de la tubería de comunicacion*/ if(pipe(fd) != 0){ fprintf(stderr, "Error en la creacion de la tuberia\n"); return EXIT_FAILURE; } //CREACION DE LOS PROCESOS HIJOS for(i=1; i<NUM_HIJOS; i++){ switch(pids[i-1]=fork()){ //Se guarda el pid en la tabla de procesos y con pids[i-1]se salta el ./padre case -1: fprintf(stderr, "Error en la creacion del proceso hijo\n"); return EXIT_FAILURE; break; case 0: //Ejecucuion por el proceso hijo close(1); if(dup(fd[1]) != 1){// Asignacion de salida estandar fprintf(stderr, "Error en la duplicacion del descriptor\n"); return EXIT_FAILURE; } if(execl(NOMBREHIJO, NOMBREHIJO, argv[i], NULL) == -1){ //argv[1] fprintf(stderr, "Error en la ejecucion del proceso hijo\n"); exit(EXIT_FAILURE); } break; default: /*Ejecucion por el proceso padre*/ close(fd[1]); break; } longitud_pid++; //Para tener un control de cuantas cosas hay dentro del pids, por ejemplo hola (longitud=1) mundo (longitud=2) } /*Espera a la finalizacion de los procesos hijos*/ for(i=1; i<NUM_HIJOS; i++){ pid=wait(NULL); //leer un caracter de entrada de la tuberia fd[0] (READ) } printf("[Proceso padre] finaliza\n"); return EXIT_SUCCESS; }
/*FinalizarProcesos: Termina todos los procesos hijos vivos*/ void FinalizarProcesos(void){ int i; for(i=0; i<longitud_pid; i++){ //Logitud_pid es porque los pids leidos van a tener valor if(kill(pids[i], SIGTERM) == -1){ fprintf(stderr, "Error al enviar una señal\n"); exit(EXIT_FAILURE); } } }
/*Manejador: Manejador de señal*/ void Manejador(int num){ FinalizarProcesos(); printf("[Proceso padre] finaliza\n"); exit(EXIT_SUCCESS); }
|
|
|
En línea
|
|
|
|
RayR
Desconectado
Mensajes: 243
|
Pues se usa igual que con cualquier tipo de archivo: read(fd[0], buffer, NUM_BYTES);
Al margen de eso, revisa bien tu código y apuntes que tengas, ya que tiene varios errores. Por mencionarte algunos: Siempre es importante cerrar los descriptors no usados, así que los hijos deberían cerrar fd[0]. De igual forma, después del dup, ya no usas fd[1] directamente (execl usa el descriptor de stdout, que apunta hacia tu pipe), por lo que también es mejor cerrarlo. Por cierto, dup2 es más recomendable que dup, aunque esto es sólo un consejo. Estás cerrando fd[1] desde dentro del bucle, lo que significa que, a partir de la segunda iteración, estarás intentado duplicar un descriptor ya cerrado. Ese close debe ir fuera del for. No estás terminando los procesos hijos, así que algunos de ellos van a crear sus propios procesos hijos, además de ejecutar lo que está fuera del bucle, adonde, se supone, sólo debería llegar el padre. Así que debes agregar un exit al final del case 0. Ya que estamos, normalmente es preferible que los procesos hijos finalicen con _exit en vez de exit. En tu caso no lo cambies, pero tenlo en cuenta. Si en algún ejercicio posterior tienes problemas (por ejemplo, que los mensajes salgan repetidos), busca las diferencias entre ambas funciones, ya que ahí podría estar la solución.
|
|
|
En línea
|
|
|
|
Andrea0000
Desconectado
Mensajes: 5
|
Gracias por tu ayuda @RayR. He intentado hacer los cambios según he entendido, pero a la hora de compilarlo no me da un error pero cuando ejecuto el proceso padre con (./padre.o hola mundo) me aparece errores como: -Error en la ejecucion del proceso hijo -[Proceso padre] finaliza Adjunto el código con los cambios. #define _POSIX_SOURCE #include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> #include <wait.h>
#define NUM_HIJOS 10//El numero de hijos debe ser tantos como numero de parametros haya #define NOMBREHIJO "./hijo"
void FinalizarProcesos();
void Manejador(int num);
pid_t pids[NUM_HIJOS]; int longitud_pid=0;//logitud del pid
int main(int argc, char *argv[]){ int fd[2];//Descriptores de la tuberia de comunicacion int i, j; //Para los bucles int pid; //PID de un proceso hijo int status; //terminacion proceso hijo /*Tratamiento de la linea de ordenes*/ if(argc < 2){// < 2 fprintf(stderr, "Error en el numero de argumentos\n"); exit(EXIT_FAILURE); } /*Tratamiento de la señal*/ if(signal(SIGINT, Manejador)== SIG_ERR){ fprintf(stderr, "Error en la manipulacion de la señal\n"); exit(EXIT_FAILURE); } /*?? Creacion de la tubería de comunicacion*/ if(pipe(fd) != 0){ fprintf(stderr, "Error en la creacion de la tuberia\n"); return EXIT_FAILURE; } //CREACION DE LOS PROCESOS HIJOS for(i=1; i<NUM_HIJOS; i++){ switch(pids[i-1]=fork()){ //Se guarda el pid en la tabla de procesos y con pids[i-1]se salta el ./padre case -1: fprintf(stderr, "Error en la creacion del proceso hijo\n"); FinalizarProcesos(); break; case 0: //Ejecucuion por el proceso hijo close(1); if(dup(fd[1]) != 1){// Asignacion de salida estandar fprintf(stderr, "Error en la duplicacion del descriptor\n"); return EXIT_FAILURE; } if(execl(NOMBREHIJO, NOMBREHIJO, argv[i], NULL) == -1){ //argv[1] fprintf(stderr, "Error en la ejecucion del proceso hijo\n"); return EXIT_FAILURE; } return EXIT_FAILURE; break; default: /*Ejecucion por el proceso padre*/ break; } longitud_pid++; //Para tener un control de cuantas cosas hay dentro del pids, por ejemplo hola (longitud=1) mundo (longitud=2) } close(fd[1]); /*Espera a la finalizacion de los procesos hijos*/ for(i=1; i<NUM_HIJOS; i++){ pid=wait(NULL); read(fd[0], pids, sizeof(pids)); //leer un caracter de entrada de la tuberia fd[0] (READ) } printf("[Proceso padre] finaliza\n"); return EXIT_SUCCESS; }
/*FinalizarProcesos: Termina todos los procesos hijos vivos*/ void FinalizarProcesos(void){ int i; for(i=0; i<longitud_pid; i++){ //Logitud_pid es porque los pids leidos van a tener valor if(kill(pids[i], SIGTERM) == -1){ fprintf(stderr, "Error al enviar una señal\n"); exit(EXIT_FAILURE); } } }
/*Manejador: Manejador de señal*/ void Manejador(int num){ FinalizarProcesos(); printf("[Proceso padre] finaliza\n"); exit(EXIT_SUCCESS); }
|
|
|
En línea
|
|
|
|
RayR
Desconectado
Mensajes: 243
|
Ese mensaje en tu programa indica que falló execl. Asegúrate de que el archivo "hijo" exista en el mismo directorio que "padre", y que sea ejecutable. Puedes ver más detalles sobre el error si después del fprintf que muestra "Error en la ejecucion del proceso hijo\n", pones:
Y te digo otra vez, revisa bien el código y lee los apuntes o manuales que tengas, porque todavía hay más errores. Por ejemplo, tu read está mal, ya que el segundo parámetro debería ser una cadena de caracteres. Y a execl le estás pasando argv[ i ]: tal y como tienes el for, eso es incorrecto. Revísalo bien y verás por qué. Los procesos hijos deberían terminar con _exit o exit, no con return; no sé por qué cambiaste eso. De cualquier forma forma, esa última línea del case 0 no debería retornar EXIT_FAILURE; eso es sólo cuando se finaliza con error. Y ahora que lo vuelvo a ver, estrictamente hablando, en tu programa no necesitarías ese último exit (o return), ya que los hijos están llamando a execl (que los reemplaza por procesos nuevos), pero de todas formas es importante acostumbrarte a finalizar siempre todos tus procesos hijos.
|
|
|
En línea
|
|
|
|
Andrea0000
Desconectado
Mensajes: 5
|
Ese mensaje en tu programa indica que falló execl. Asegúrate de que el archivo "hijo" exista en el mismo directorio que "padre", y que sea ejecutable. Puedes ver más detalles sobre el error si después del fprintf que muestra "Error en la ejecucion del proceso hijo\n", pones: Si, tanto el proceso padre como el proceso hijo ambos estan en el mismo directorio, he puesto la linea de codigo que me has dicho y cuando ejecuto me devuelve: Error en la ejecucion del proceso hijo execl: No such file or directory He intentado solucionarlo, pero segun he visto en los apuntes y en el manual no he conseguido ver los fallos, no se porque tiene fallos de directorio, si tanto el hijo como el padre estan en el mismo directorio
Por ejemplo, tu read está mal, ya que el segundo parámetro debería ser una cadena de caracteres. Y a execl le estás pasando argv[ i ]: tal y como tienes el for, eso es incorrecto. Revísalo bien y verás por qué. -Ahi he creado un buffer de lectura/escritura, creo que con ello me basta aunque tenia dudas de que en vez de crear un buffer poner la variable NOMBREHIJO -En cuanto al for no se a cual de los dos se refiere, pero he analizado ambos y no encuentro lo que dices que es incorrecto, no se si te refieres a esto: if(execl(NOMBREHIJO, NOMBREHIJO, argv[1], NULL) == -1){ //argv[1] fprintf(stderr, "Error en la ejecucion del proceso hijo\n"); perror("execl"); exit(EXIT_FAILURE); alli en vez de argv , he puesto argv[1], no se si ese seria el fallo que me dices... [/b]
Los procesos hijos deberían terminar con _exit o exit, no con return; no sé por qué cambiaste eso. De cualquier forma forma, esa última línea del case 0 no debería retornar EXIT_FAILURE; eso es sólo cuando se finaliza con error. Y ahora que lo vuelvo a ver, estrictamente hablando, en tu programa no necesitarías ese último exit (o return), ya que los hijos están llamando a execl (que los reemplaza por procesos nuevos), pero de todas formas es importante acostumbrarte a finalizar siempre todos tus procesos hijos
Y esto es cierto acabo de fijarme en los manuales y es asi como dice. Gracias!
adjunto el codigo del proceso padre nuevamente y el del hijo a continuacion:
HIJO
#include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <sys/stat.h>
int main(int argc, char *argv[]){
/*Tratamiento de la linea de ordenes*/ if(argc != 2){ fprintf(stderr, "Error en el numero de argumentos\n"); return EXIT_FAILURE; } //Para las señales sleep(5); //El hijo se ejecuta se duerme 5 seg y va ha inprimir el 1º caracter por tubería //Ve como se matan los procesos hijos. putchar(argv[1][0]); //El primer caracter en la salida estandar y escribe en la tuberia, imprime el primer caracter return EXIT_SUCCESS; }
PADRE#define _POSIX_SOURCE #include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> #include <wait.h>
#define NUM_HIJOS 10//El numero de hijos debe ser tantos como numero de parametros haya #define NOMBREHIJO "./hijo" #define MAXBUFFER 256 //Tamaño del buffer lectura/escritura
void FinalizarProcesos();
void Manejador(int num);
pid_t pids[NUM_HIJOS]; int longitud_pid=0;//logitud del pid
int main(int argc, char *argv[]){ int fd[2];//Descriptores de la tuberia de comunicacion int i, j; //Para los bucles int pid; //PID de un proceso hijo int status; //terminacion proceso hijo char buffer[MAXBUFFER];//buffer de lectura/escritura /*Tratamiento de la linea de ordenes*/ if(argc < 2){// < 2 fprintf(stderr, "Error en el numero de argumentos\n"); exit(EXIT_FAILURE); } /*Tratamiento de la señal*/ if(signal(SIGINT, Manejador)== SIG_ERR){ fprintf(stderr, "Error en la manipulacion de la señal\n"); exit(EXIT_FAILURE); } /*?? Creacion de la tubería de comunicacion*/ if(pipe(fd) != 0){ fprintf(stderr, "Error en la creacion de la tuberia\n"); return EXIT_FAILURE; } //CREACION DE LOS PROCESOS HIJOS for(i=1; i<NUM_HIJOS; i++){ switch(pids[i-1]=fork()){ //Se guarda el pid en la tabla de procesos y con pids[i-1]se salta el ./padre case -1: fprintf(stderr, "Error en la creacion del proceso hijo\n"); FinalizarProcesos(); break; case 0: //Ejecucuion por el proceso hijo close(1); if(dup(fd[1]) != 1){// Asignacion de salida estandar fprintf(stderr, "Error en la duplicacion del descriptor\n"); return EXIT_FAILURE; } if(execl(NOMBREHIJO, NOMBREHIJO, argv[1], NULL) == -1){ //argv[1] fprintf(stderr, "Error en la ejecucion del proceso hijo\n"); perror("execl"); exit(EXIT_FAILURE); } break; default: /*Ejecucion por el proceso padre*/ //close(fd[1]);// debe de ir fuera del for break; } longitud_pid++; //Para tener un control de cuantas cosas hay dentro del pids, por ejemplo hola (longitud=1) mundo (longitud=2) } close(fd[1]); /*Espera a la finalizacion de los procesos hijos*/ for(i=1; i<NUM_HIJOS; i++){ pid=wait(NULL); read(fd[0], buffer, sizeof(buffer));//leerá la tuberia y la escribirá en la salida estandar //leer un caracter de entrada de la tuberia fd[0] (READ) } printf("[Proceso padre] finaliza\n"); return EXIT_SUCCESS; }
/*FinalizarProcesos: Termina todos los procesos hijos vivos*/ void FinalizarProcesos(void){ int i; for(i=0; i<longitud_pid; i++){ //Logitud_pid es porque los pids leidos van a tener valor if(kill(pids[i], SIGTERM) == -1){ fprintf(stderr, "Error al enviar una señal\n"); exit(EXIT_FAILURE); } } }
/*Manejador: Manejador de señal*/ void Manejador(int num){ FinalizarProcesos(); printf("[Proceso padre] finaliza\n"); exit(EXIT_SUCCESS); }
|
|
|
En línea
|
|
|
|
RayR
Desconectado
Mensajes: 243
|
Eso indica que no encuentra el archivo. ¿Seguro que se llama "hijo" y no "hijo.o" o algo así? Porque al parecer el ejecutable principal se llama "padre.o" (que realmente no debería tener esa extensión, pero eso es otro tema). De cualquier forma, puedes probar abriendo una terminal y desde el mismo directorio desde el que ejecutas padre, ejecuta el comando ./hijo, y ve si funciona. En cuanto a argv, me refería a este for: for(i=1; i<NUM_HIJOS; i++){
Como NUM_HIJOS vale 10, i tomará valores desde 1 a 9. Si al programa le pasas menos de 9 argumentos, llega un punto en el que con argv[ i ] estarás intentando ir más allá del final de argv. Nota también que el hecho de iniciar el for desde 1 significa que realmente estás limitando el número máximo de hijos a 9, no a 10, aunque creo que es un detalle sin mucha importancia. Veo que luego vas a tener que imprimir lo que read lea. Algo que causa muchos problemas es olvidar que el búfer que te da esa función no necesariamente contiene caracter nulo '\0', así que es importante verificar el valor que te devuelve (el número de bytes leídos) y, o cierras manualmente la cadena, o le indicas a printf el número de caracteres a imprimir. Por ejemplo: if ((num_caracteres = read(fd[0], buffer, MAXBUFFER)) > 0) printf("%.*s", num_caracteres , buffer );
Y te reitero, los hijos deberían cerrar fd[0], y, después del dup, fd[1]. Aunque en este caso no te dará problemas, es una mala práctica no hacerlo. Caso completamente distinto al del último exit de ese case 0, que, como te dije en el mensaje anterior, es redundante (aunque tampoco hace ningún mal). Al escribir mi primera respuesta, me enfoqué en los problemas con los pipes y fork y ni siquiera me fijé en que los hijos ejecutaban execl. Obviamente, al llamar a las funciones exec*, sólo es necesario finalizar la ejecución en caso de error, lo cual ya haces.
|
|
|
En línea
|
|
|
|
|
Mensajes similares |
|
Asunto |
Iniciado por |
Respuestas |
Vistas |
Último mensaje |
|
|
algunas dudas en programacion BATCH(nuevo en esto de programacion)
Scripting
|
stock_C
|
8
|
9,429
|
19 Junio 2009, 18:08 pm
por frank30
|
|
|
programacion web vs programacion de escritorio
Programación General
|
lupitapro
|
2
|
7,873
|
29 Mayo 2010, 05:51 am
por Dreamaker
|
|
|
Programacion Estructurada Vs Programacion Orientada a Objetos
Programación General
|
79137913
|
3
|
8,666
|
1 Junio 2011, 18:02 pm
por 79137913
|
|
|
Programacion en C
Programación C/C++
|
Nachoppp
|
0
|
1,307
|
2 Mayo 2018, 00:51 am
por Nachoppp
|
|
|
programacion
Programación C/C++
|
alex dom
|
1
|
1,405
|
16 Noviembre 2018, 22:28 pm
por K-YreX
|
|