Gica78R
29-04-2005, 18:47
Ciao!
Ho scritto un programmino che forka alcune volte creando un paio di processi figli, e uno di questi figli forka a sua volta per creare un... nipote :)
Tutti i processi devono semplicemente scrivere delle righe su un file aperto dal padre e, prima di terminare, ciascun processo deve attendere che i rispettivi figli abbiano terminato. Per questo utilizzo la funzione int waitpid(pid_t pid, int *status, int options), ma nel caso del processo che genera il 'nipote' a quanto pare questa funzione non si blocca in attesa che il nipote termini (lo si vede dall' output...)
Secondo voi da cosa puo' dipendere?
Nel caso la mia esposizione del problema fosse poco chiara (parlo un po' criptato... :p ), vi posto il listato...
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/wait.h>
#define NUMVOLTE 40000
#define SEMKEY 500
#define LOOP 5000
int main()
{
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
/*Pongo stdout in modalita' UNBUFFERED */
setvbuf(stdout,NULL,_IONBF,0);
/* Dichiarazioni ed inizializzazioni delle strutture relative al file di output */
FILE *f;
char *nomefile="/provafiles.txt";
char nome[PATH_MAX];
memset((void*)nome,0,PATH_MAX);
strncpy(nome,getenv("PWD"),PATH_MAX);
if(strlen(nome)+strlen(nomefile)>PATH_MAX)
{
printf("Il path generato e' troppo lungo; il programma verra' terminato!\n");
exit(EXIT_FAILURE);
}
strncat(nome,nomefile,NAME_MAX);
/* Dichiarazione strutture relative al semaforo */
int semid;
const union semun semunion={1};
struct sembuf semw={0,-1,SEM_UNDO};
struct sembuf sems={0,1,SEM_UNDO};
/* Creazione ed inizializzazione semaforo */
semid=semget(SEMKEY,1,IPC_CREAT|IPC_EXCL|666);
if(semid<0)
{
perror("Errore semaforo");
exit(EXIT_FAILURE);
}
if(semctl(semid,0,SETVAL,semunion)<0)
{
perror("Errore init semaforo");
semctl(semid,0,IPC_RMID);
exit(EXIT_FAILURE);
}
/* Apertura in scrittura esclusiva del file per l'output;
se il file esiste gia', il programma termina /*
if ((f=fopen(nome,"wx"))==NULL)
{
perror("Errore nell'apertura del file");
exit(EXIT_FAILURE);
}
/* Pongo il file in modalita' UNBUFFERED */
setvbuf(f,NULL,_IONBF,0);
pid_t pid,pid2;
if ((pid=fork())==0)
{
/* PRIMO FIGLIO */
setvbuf(f,NULL,_IONBF,0);
if((pid2=fork())==0)
{
/* NIPOTE */
setvbuf(f,NULL,_IONBF,0);
int i,j;
for(i=0;i<NUMVOLTE;i++)
{
if((i+1)%100==0)
{
semop(semid,&semw,1); //WAIT sul semaforo
fprintf(f,"E' il nipote che scrive... %d\n",i+1);
semop(semid,&sems,1); //SIGNAL sul semaforo
for(j=0;j<LOOP;j++); // Ciclo vuoto per ritardare il nipote
}
}
return EXIT_SUCCESS;
} // FINE NIPOTE
/* PRIMO FILGLIO */
int i;
for(i=0;i<NUMVOLTE;i++)
if ((i+1)%100==0)
{
semop(semid,&semw,1); //WAIT semaforo
fprintf(f,"E' il primo figlio che scrive... %d\n",i+1);
semop(semid,&sems,1); //SIGNAL semaforo
}
int status;
waitpid(pid2,&status,1); //Attende la fine di NIPOTE
/* Quando NIPOTE termina, lo scrive sul file */
semop(semid,&semw,1);
fprintf(f,"Sono il primo figlio, il nipote e' terminato con lo stato %d\n",status);
semop(semid,&sems,1);
return EXIT_SUCCESS;
} // FINE PRIMO FIGLIO
else
{
/* PADRE */
if((pid2=fork())==0) //Crea un secondo figlio
{
/* SECONDO FIGLIO
int i;
for(i=0;i<NUMVOLTE;i++)
if((i+1)%100==0)
{
semop(semid,&semw,1);
fprintf(f,"E' il secondo figlio che scrive... %d\n",i+1);
semop(semid,&sems,1);
}
return EXIT_SUCCESS;
} // FINE SECONDO FIGLIO
int i;
for(i=0;i<NUMVOLTE;i++)
if ((i+1)%100==0)
{
semop(semid,&semw,1);
fprintf(f,"E' il padre che scrive... %d\n",i+1);
semop(semid,&sems,1);
}
}
//int status;
waitpid(pid,NULL,1); // Attende la fine del PRIMO FIGLIO
waitpid(pid2,NULL,1); // Attende la fine del SECONDO FIGLIO
fclose(f);
semctl(semid,0,IPC_RMID); //Rimuove il semaforo
printf("Programma terminato con successo...\n");
return 0;
}
Non commentate sull'utilita' del programma :D, e' solo per capire come usare certe funzioni e per avere un'idea di come funziona lo scheduler...
Per ciascuna scrittura sul file, uso un semaforo per accedervi in modo esclusivo; inoltre ho fatto in modo che l'accesso al file non sia bufferizzato.
Grazie per ogni suggerimento...
Gica
30/4/05, aggiornamento: ho aggiunto qualche commento al codice... :)
Ho scritto un programmino che forka alcune volte creando un paio di processi figli, e uno di questi figli forka a sua volta per creare un... nipote :)
Tutti i processi devono semplicemente scrivere delle righe su un file aperto dal padre e, prima di terminare, ciascun processo deve attendere che i rispettivi figli abbiano terminato. Per questo utilizzo la funzione int waitpid(pid_t pid, int *status, int options), ma nel caso del processo che genera il 'nipote' a quanto pare questa funzione non si blocca in attesa che il nipote termini (lo si vede dall' output...)
Secondo voi da cosa puo' dipendere?
Nel caso la mia esposizione del problema fosse poco chiara (parlo un po' criptato... :p ), vi posto il listato...
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/wait.h>
#define NUMVOLTE 40000
#define SEMKEY 500
#define LOOP 5000
int main()
{
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
/*Pongo stdout in modalita' UNBUFFERED */
setvbuf(stdout,NULL,_IONBF,0);
/* Dichiarazioni ed inizializzazioni delle strutture relative al file di output */
FILE *f;
char *nomefile="/provafiles.txt";
char nome[PATH_MAX];
memset((void*)nome,0,PATH_MAX);
strncpy(nome,getenv("PWD"),PATH_MAX);
if(strlen(nome)+strlen(nomefile)>PATH_MAX)
{
printf("Il path generato e' troppo lungo; il programma verra' terminato!\n");
exit(EXIT_FAILURE);
}
strncat(nome,nomefile,NAME_MAX);
/* Dichiarazione strutture relative al semaforo */
int semid;
const union semun semunion={1};
struct sembuf semw={0,-1,SEM_UNDO};
struct sembuf sems={0,1,SEM_UNDO};
/* Creazione ed inizializzazione semaforo */
semid=semget(SEMKEY,1,IPC_CREAT|IPC_EXCL|666);
if(semid<0)
{
perror("Errore semaforo");
exit(EXIT_FAILURE);
}
if(semctl(semid,0,SETVAL,semunion)<0)
{
perror("Errore init semaforo");
semctl(semid,0,IPC_RMID);
exit(EXIT_FAILURE);
}
/* Apertura in scrittura esclusiva del file per l'output;
se il file esiste gia', il programma termina /*
if ((f=fopen(nome,"wx"))==NULL)
{
perror("Errore nell'apertura del file");
exit(EXIT_FAILURE);
}
/* Pongo il file in modalita' UNBUFFERED */
setvbuf(f,NULL,_IONBF,0);
pid_t pid,pid2;
if ((pid=fork())==0)
{
/* PRIMO FIGLIO */
setvbuf(f,NULL,_IONBF,0);
if((pid2=fork())==0)
{
/* NIPOTE */
setvbuf(f,NULL,_IONBF,0);
int i,j;
for(i=0;i<NUMVOLTE;i++)
{
if((i+1)%100==0)
{
semop(semid,&semw,1); //WAIT sul semaforo
fprintf(f,"E' il nipote che scrive... %d\n",i+1);
semop(semid,&sems,1); //SIGNAL sul semaforo
for(j=0;j<LOOP;j++); // Ciclo vuoto per ritardare il nipote
}
}
return EXIT_SUCCESS;
} // FINE NIPOTE
/* PRIMO FILGLIO */
int i;
for(i=0;i<NUMVOLTE;i++)
if ((i+1)%100==0)
{
semop(semid,&semw,1); //WAIT semaforo
fprintf(f,"E' il primo figlio che scrive... %d\n",i+1);
semop(semid,&sems,1); //SIGNAL semaforo
}
int status;
waitpid(pid2,&status,1); //Attende la fine di NIPOTE
/* Quando NIPOTE termina, lo scrive sul file */
semop(semid,&semw,1);
fprintf(f,"Sono il primo figlio, il nipote e' terminato con lo stato %d\n",status);
semop(semid,&sems,1);
return EXIT_SUCCESS;
} // FINE PRIMO FIGLIO
else
{
/* PADRE */
if((pid2=fork())==0) //Crea un secondo figlio
{
/* SECONDO FIGLIO
int i;
for(i=0;i<NUMVOLTE;i++)
if((i+1)%100==0)
{
semop(semid,&semw,1);
fprintf(f,"E' il secondo figlio che scrive... %d\n",i+1);
semop(semid,&sems,1);
}
return EXIT_SUCCESS;
} // FINE SECONDO FIGLIO
int i;
for(i=0;i<NUMVOLTE;i++)
if ((i+1)%100==0)
{
semop(semid,&semw,1);
fprintf(f,"E' il padre che scrive... %d\n",i+1);
semop(semid,&sems,1);
}
}
//int status;
waitpid(pid,NULL,1); // Attende la fine del PRIMO FIGLIO
waitpid(pid2,NULL,1); // Attende la fine del SECONDO FIGLIO
fclose(f);
semctl(semid,0,IPC_RMID); //Rimuove il semaforo
printf("Programma terminato con successo...\n");
return 0;
}
Non commentate sull'utilita' del programma :D, e' solo per capire come usare certe funzioni e per avere un'idea di come funziona lo scheduler...
Per ciascuna scrittura sul file, uso un semaforo per accedervi in modo esclusivo; inoltre ho fatto in modo che l'accesso al file non sia bufferizzato.
Grazie per ogni suggerimento...
Gica
30/4/05, aggiornamento: ho aggiunto qualche commento al codice... :)