Programa procesos en C

Iniciado por ferminta, 13 Enero 2012, 21:57 PM

0 Miembros y 1 Visitante están viendo este tema.

ferminta

tengo un Caso de procesos concurrentes que no logro ver donde falla:


Se trata de la realización de un programa en C llamado padre que deberá crear un proceso "hijo" el cual deberá calcular los 10 primeros números de la sucesión de Fibonacci e imprimirlos por salida estándar (formato " HIJO: fibonacci % N =%M\n "
donde %N y %M representan el índice y el valor del correspondiente número de la sucesión)

Mientras el "hijo" realiza el cálculo, el "padre" deberá esperar a que termine. Una vez haya terminado, el hijo comunicará al proceso "padre" la información necesaria para poder continuar con el cálculo de la sucesión. De esa manera el padre podrá continuar y calcular los siguientes 10 números de la sucesión e imprimirlos por salida estándar (formato " PADRE: fibonacci %N=%M\n"
donde %N y %M representan el índice y el valor del correspondiente número de la sucesión)
Se trata de que el  "padre" no deberá nunca calcular la sucesión desde el inicio.




Resuelvo el problema  creando un proceso hijo, realizando la llamada al sistema fork.
Después compruebo si estoy  en el proceso hijo, y entonces ejecuto diez iteraciones de la sucesión de Fibonacci :  if (fork()==0.....etc.., y voy pintando por pantalla los resultados

A partir de aquí debe continuar el proceso padre, después de que el hijo haga un exit al terminar el bucle:
Puntos:
1-       Escribo  un wait para que el padre espere a que termine el hijo.
2-        Antes de que el hijo haga el exit, paso al proceso padre los dos últimos valores que calculó el proceso hijo, para que el padre siga con la serie.

El punto dos al tratarse de dos procesos independientes (cada uno con su PID) ejecutándose de manera concurrente, utilizo de un mecanismo de comunicación entre procesos para pasar estas variables de un proceso a otro.
(paso los valores de la serie de Fibonacci t9 y t10 del hijo al padre (para que este último calcule el t11):

Después de calcular el hijo los valores de la serie y haberlos almacenado en un array 1..10, utilizo dos tuberías sin nombre,las abrire en el extremo de escritura y pasar los dos últimos valores del array, uno en cada tubería. El padre, después de que el hijo haga el exit, leerá las tuberías y con estos valores seguirá con la serie.


En código:

#define N=10
#include<stdio.h>
#define M
#include<unistd.h>
#include<stdlib.h>
#include<wait.h>

int main ()
{
int tabla[10];
int i,j;
int estadohijo;
int sig;
int mipipeone[2];
int mipipetwo[2];
int leido1,leido2;

pipe(mipipeone);
pipe(mipipetwo);
if(fork()==0)
{
printf("Proceso hijo/n");
printf("%d/n",0);
scanf("%d",& tabla[0]);
printf("%d/n",1);
scanf("%d",& tabla[1]);

for (i=2;i<=10;i++)
{
tabla=tabla[i-1] + tabla[i-2];
scanf("%d",tabla);
printf("%d", tabla);
}
write(mipipeone[1],tabla[9],1);
write(mipipetwo[1],tabla[10],1);
exit;
else
{
wait (& estadohijo);
printf ("Proceso Padre/n");
leido1=read(mipipeone[0],tabla[9],1);
leido2=read(mipipetwo[0],tabla[10],1);
sig=leido1+leido2;
scanf("%d",sig);
printf("%d",sig]);
while (j<M)
{
leido2=sig;
sig=sig+leido2;
scanf("%d",sig);
printf("%d",sig]);
}
   }

Xandrete

#1
¡Hola, jef@!

Me encanta tu problema. Es interesante. No difícil, pero sí interesante.

Un consejo, de cara al futuro, utiliza las etiquetas dedicadas a introducir código, [ code=LENGUAJEDEPROGRAMACION ][ /code ], el código será mucho más legible desde el foro. También sería útil decir en qué falla. ¿No compila? ¿El resultado no es correcto? De todas formas, tu forma de explicar el problema ha sido suficientemente clara como para poder ayudar. Asumo que programas en un entorno Linux (por la inclusión de unistd, más que nada :)).

Tu forma de plantearte la solución es la correcta. De todas formas, la concurrencia del programa es "débil", porque el padre ha de esperar mientras el hijo hace faena. Y lo que si que no entiendo es que por lo que dices, tu programa no tiene entrada de datos por parte del usuario, así que no sé por que motivo haces scanf en varios puntos de tu código. Tampoco sé por qué usas dos pipes, si la comunicación es unilateral (el hijo comunica datos al padre, pero no al revés).

Continúo. Si no vas a leer el estado de finalización de un hijo, puedes hacer wait(NULL) (es preferible a declarar una variable que no vas a utilizar). El formato de salida que utilizas tampoco es el que indicas (HIJO: fibonacci % N =%M\n)...

Ahora me voy a cenar. En un rato vengo y me pongo con esto otra vez :)


EI: juntando mensajes.

Ya estoy aquí.

Uno de tus fallo es que no inicializas bien los arrays. Utilizas la función scanf, pero eso es para entrar datos del usuario. Si quieres que la posición x de un array tenga el valor y, haces array[ x ] = y. Además, tan pronto como sepas que no vas a usar un canal CIÉRRALO. ¿Sabes lo que es un abrazo mortal? No, no es un achuchón de estos que hacen que se te salten los ojos. Se le llama abrazo mortal a la situación en que un proceso A espera a que finalice otro proceso B, y el proceso B a su vez espera que finalice A. Evidentemente, de esta manera no acabarán nunca. Bueno, pues si no cierras canales, te expones a que suceda algo así. Es por eso que conviene abrir el menor número de pipes posible (y en este caso, te aseguro que sólo hace falta una, sólo se necesitan 2 cuando se requiere comunicación bilateral).

Por otro lado, le pasas mal el tercer parámetro tanto al write como al read. Ten en cuenta que el tercer parámetro es el número de bytes a escribir/leer. Aunque depende de la máquina, un int suele tener ser de 4 bytes (pero depende del procesador, de la implementación del compilador...). Para asegurarte el tiro y ganar en portabilidad, en vez de utilizar el valor 4 para enteros usa sizeof(int). Sizeof() es un operador que te devuelve el número de bytes que conforman cierto objeto o tipo de dato. Además, para ahorrar llamadas al sistema, puedes escribir en la pipe dos enteros de una tacada haciendo write(fdpipe[1],&tabla[8],2*sizeof(int)). De esta manera, escribes en la pipe tanto el valor de la posición 8 de tabla como de la posición 9.

Y aquí van dos errores más. Tanto en write como en read se utilizan punteros. Tu usas tabla[9] y tabla[10], y esto está mal (tabla[9] es un entero, y tú lo que tienes que hacer es pasarle el puntero a ese entero). La función read/write tratará de desreferenciar lo que le hayas pasado como parámetro, y si le pasas tabla[9] (que por poner algo, digamos que vale 10), intentará escribir/leer en/de la posición 10 de memoria. El segundo error es que no has tenido en cuenta que los índices de los vectores empiezan en el 0 a la hora de intentar pasarle al padre el noveno y décimo números de Fibonacci. Si quieres poner 10 números de Fibonacci en una tabla, el primero estará en la posición 0 y el décimo en la posición 9. Así, si quieres pasarle los números de Fibonacci 9 y 10 tienes que pasarle tabla[8] y tabla[9].

Bueno, te paso el código que he hecho yo para este problema, por si quieres tener algún ejemplo.

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

void addTenFib(int* vector, int start) {
int i;
if (start == 0) {
vector[0] = vector[1] = 1;
i = 2;
}
else i = start;
while (i < start + 10) {
vector[i] = vector[i-1] + vector[i - 2];
++i;
}
}

int main () {
int tabla[20];
int fdpipe[2];
int i;
pipe(fdpipe);
if (fork() == 0) {
close(fdpipe[0]);
addTenFib(tabla,0);
for (i = 0; i < 10; ++i)
printf("HIJO: fibonacci %d: %d\n",i+1,tabla[i]);
write(fdpipe[1],tabla,10*sizeof(int));
exit(0);
}
close(fdpipe[1]);
wait(NULL);
read(fdpipe[0],tabla,10*sizeof(int));
close(fdpipe[0]);
addTenFib(tabla,10);
for (i = 10; i < 20; ++i)
printf("PADRE: fibonacci %d: %d\n",i+1,tabla[i]);
return 0;
}


Le he pasado toda la tabla al padre, aunque no hiciera falta. Así puedes comprobar que no hace falta una decena de pipes y una decena de líneas para pasar 10 valores. Se puede hacer así de fácil.

No he hecho comprobación de errores (por ejemplo, no he tenido en cuenta que el fork puede fallar y que el read puede leer menos bytes de los que le índico). Para ello se puede incluir errno (para, en caso de error, informar al usuario acerca del error exacto) e incluir unas cuantas líneas con mandangas para asegurarnos de que el programa no continúa si algo falla.

En fin, espero haberte ayudado y que hayas entendido todo lo que te he explicado.

¡Saludos!

EDITO: Casi se me olvida. ¿Por qué defines una macro si despues no la usas? Me refiero a #define N=10 (que por cierto, se debería escribir #define N 10, en la definición de macros no va el signo igual).

ferminta

#2
Muchas gracias; sabes un huevo y se agradece mucho tu ayuda. Voy a compilar el algoritmo y tomo muy buena nota de todo lo que me dices. Muchas gracias de nuevo por todo y saludos cordiales

EI: juntando mensajes.

Esta mañana he intentado compilar gcc
el programa  pero me sale un error  así: Le he llamado a un archivo.c  todo ese código fibprocess.c   y el error es

fibprocess.c:79:2:error in the function main expected declration statement at the end of input. No puedo sacar mucha información de ese error para corregirlo.
Saben que puede ser no puedo compilar gcc al salirme esto y por tanto tampoco obtener el archivo de salida con los resultados

Muchas gracias por adelantado

Xandrete

#3
¿Con qué código te sale? ¿Es con otro, no? El mío lo he probado con -Wall y -Werror (siempre compilo con estas dos opciones) y no me da error.

Ve a la línea 79 de tu código y mira si hay algo raro. El error que dices sale, si no me equivoco, cuando te has olvidado poner llaves de cierre (}). Mira a ver si es así.

Si indentas bien tu código, es menos probable que te sucedan este tipo de cosas. Utiliza un buen editor de texto, como Geany, Gedit (con interfaz gráfica), Emacs, Vim o Nano (modo consola). O utiliza un programa de indentado, como el indent (sí, muy original el nombre).

Saludos.

Gallu

Hola , seguramente lo habrás copiado incompleto , yo lo intente compilar con gcc y compilo a la primera sin ninguna opción especial , pero cuando le quite la última llave , la llave de cierre del main , el compilador me dío el siguiente mensaje , te suena ?


Código (bash) [Seleccionar]

pc@pc:~/Documentos/fuente$ gcc -g -o proce proce.c
proce.c: En la función 'main':
proce.c:40:1: error: expected declaration or statement at end of input


Saludos
Nadie alcanza la meta con un solo intento, ni perfecciona la vida con una sola rectificación, ni alcanza altura con un solo vuelo.

ferminta

#5
ese es justo el error que sale... voy a mirarlo. Gracias y disculpad las molestias

EI: juntando mensajes.

correcto me faltaba la ultima llave: que tonto soy!

EI: otra vez.

bueno lo peor supongo está hecho.No obstante ahora al ejecutar el programa con geany no obtengo resultado o más bien

(program exited with code:127) Press returno to continue

Debiera sacar un fichero de salida con la serie de Fibonachi de los cuales los 10 priemros terminos los saca el hijo y el resto el padre, aunque no distinguiré en la salida supongo.

EI: y otra mas ...

a ver si me ayudan a  ver porque no sale nada en la ejecución de este programa:
Un ejemplo de ejecución sería:
HIJO: Fibonachi 0=0
HIJO: Fibonachi 1=1
PADRE: Fibonachi 2=1
PADRE: Fibonachi 3 =2
.....

Xandrete

#6
 :huh:

¿De qué estamos hablando? ¿Del mismo problema? Yo había entendedido desde un principio que la salida tendría ser así:

HIJO: fibonacci 1: 1
HIJO: fibonacci 2: 1
HIJO: fibonacci 3: 2
HIJO: fibonacci 4: 3
HIJO: fibonacci 5: 5
HIJO: fibonacci 6: 8
HIJO: fibonacci 7: 13
HIJO: fibonacci 8: 21
HIJO: fibonacci 9: 34
HIJO: fibonacci 10: 55
PADRE: fibonacci 11: 89
PADRE: fibonacci 12: 144
PADRE: fibonacci 13: 233
PADRE: fibonacci 14: 377
PADRE: fibonacci 15: 610
PADRE: fibonacci 16: 987
PADRE: fibonacci 17: 1597
PADRE: fibonacci 18: 2584
PADRE: fibonacci 19: 4181
PADRE: fibonacci 20: 6765

Y que el flujo del programa tenía que ser:

1.- Padre crea pipe
2.- Padre crea hijo
3.- Padre espera finalización del hijo
4.- Hijo calcula los 10 primeros números de la secuencia de Fibonacci y los muestra por pantalla.
5.- Hijo envía datos al padre mediante la pipe para continuar la secuencia con 10 números más
6.- Hijo finaliza y padre retorna del wait
7.- Padre lee pipe.
8.- Padre calcula 10 números de fibonacci más y los muestra por pantalla.

No entiendo cuál es el problema. Si te sirve, aquí hay una versión de mi código mejorada (y modificada para que los dos primeros números de la secuencia sean 0 y 1, no 1 y 1). Repito que, para un programa más completo, se debería añadir comprobación de errores.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#define N 4

void nextFib(int vec[2]) {
int aux = vec[0];
vec[0] = vec[1];
vec[1] += aux;
}

int main () {
int tabla[2],fdpipe[2];
int i;
pipe(fdpipe);
if (fork() == 0) {
close(fdpipe[0]);
tabla[0] = 0;
tabla[1] = 1;
for (i = 0; i < N; ++i) {
printf("HIJO: Fibonacci %d: %d\n",i,tabla[0]);
nextFib(tabla);
}
write(fdpipe[1],&tabla[0],2*sizeof(int));
exit(0);
}
close(fdpipe[1]);
wait(NULL);
read(fdpipe[0],tabla,2*sizeof(int));
close(fdpipe[0]);
for (i = N; i < 2*N; ++i) {
printf("PADRE: Fibonacci %d: %d\n",i,tabla[0]);
nextFib(tabla);
}
return 0;
}


Saludos

EI: juntando mensajes.

Por cierto, ¿se ha declarado el año internacional de la secuencia de Fibonacci? Últimamente, en el foro veo muchísimos problemas que relacionados con esta sucesión.

ferminta

es correcto. Miraremos la biografia del señor FIBONACHI dado que nos ha quitado muchas horas a mucha gente. Yo me pongo a compilar de nuevo y a ejecutar a ver donde está el gazapo que tengo o hago.Buenas noches, gracias y buena suerte

Xandrete

Cita de: ferminta en 17 Enero 2012, 05:49 AM
es correcto. Miraremos la biografia del señor FIBONACHI dado que nos ha quitado muchas horas a mucha gente. Yo me pongo a compilar de nuevo y a ejecutar a ver donde está el gazapo que tengo o hago.Buenas noches, gracias y buena suerte

De nada.

En este caso, el señor Fibonacci no tiene mucha culpa. Este es un problema de gestión de procesos y de comunicación entre ellos. La secuencia de Fibonacci es sólo un pretexto: lo que importa no es la tarea que realizan los procesos, sino como la realizan.

Por otro lado, Fibonacci nunca propuso la secuencia que lleva su nombre como tal. Sólo la mencionó una vez en un libro de problemas de matemáticas, donde la empleó como módelo de reproducción de los conejos. Nunca le dio más importancia más allá de los conejos.

Saludos