|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Member
Iscritto dal: Jun 2009
Messaggi: 38
|
[C] Programmazione di sistema: fork \ pipes
Salve a tutti, è da un pò di tempo che sono appresso ad un progetto in cui sto incontrando alcuni problemi riguardanti la creazione e la "manutenzione" di più processi child nati dallo stesso parent.
La funzione ghostkeeper (parent) dovrebbe essere in grado di capire quando uno dei 4 ghost (childs) termina, e crearne a sua volta un'altro identico. In poche parole i processi child devono sempre rimanere 4. Ed è ciò che non riesco a fare. Tutto ok quando partono i primi 4, ma quando uno dei 4 primi fa la exit cominciano i problemi: processi che si moltiplicano o che non nascono direttamente. Forse mi spiego meglio con il codice: intanto gli header che uso sono i seguenti: Codice:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <curses.h> #include <signal.h> #include <sys/wait.h> Codice:
void ghostkeeper (void) {
my_pid = getpid();
close(pipe_pids[0]);
write(pipe_pids[1],&my_pid,sizeof(my_pid));
pid_t id[4]; // id[i] : il PID del fantasma con id "i"
int death_id = 0;
int i;
// handler dei segnali dei figli
signal (SIGCHLD, sigchld_h);
// faccio la fork per il fantasma e annoto il PID
for(i=0;i<4;i++) {
if(pid_ghost[i]=fork() == 0) ghost(i);
id[i]=pid_ghost[i];
}
// ora so che tutti i fantasmi sono entrati e conosco il loro PID
// rimaniamo in lettura sulla pipe aspettando che un fantasma muoia
// (quando un fantasma muore scrive su questa pipe il suo ID
// ############ questo è ciò che non funziona #
// ####################################
while(1) {
close(pipe_ghost_death[1]);
read(pipe_ghost_death[0],&death_id,sizeof(death_id));
pid_ghost[death_id]=0;
if(pid_ghost[death_id]=fork() == 0) ghost(death_id);
id[death_id] = pid_ghost[death_id];
}
// fa un casino della malora
// guardare cosa succede nei processi sul monitor di sistema
// con il codice fantasma che va in exit dopo un tot di secondi
// ########################################
}
Codice:
void ghost (int id) {
int x = 0;
// il processo una volta pronto per fare la exit dovrebbe comunicare
// tramite la pipe il suo id in modo che ghostkeeper crei un altro processo
while(x++ < 4+(2*id)) sleep(1);
// prima di andare in exit deve comunicare tramite questa pipe
// al ghostkeeper che il proprio ID (1 dei 4) sta per essere liberato
close(pipe_ghost_death[0]);
write(pipe_ghost_death[1],&id,sizeof(id));
// ed esce
exit(0);
}
|
|
|
|
|
|
#2 |
|
Senior Member
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
|
vedo che hai installato un signal handler per SIGCHLD... non e' che magari ricrei il processo anche la' ?
cmq io la farei piu' semplice. Ad esempio potresti, una volta creati i processi, usare una wait(2) per aspettare che uno dei figli muoia. La wait stessa ti ritorna il pid del processo morto e quindi puoi fare ripartire quello che ti interessa. mi sembra molto piu' semplice.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele |
|
|
|
|
|
#3 |
|
Member
Iscritto dal: Jun 2009
Messaggi: 38
|
ok grazie mille del consiglio, stasera appena avrò il progetto completo davanti vedrò di implementarlo con la wait
EDIT: << il signal handler fa una waitpid di questo genere quà: Codice:
while ( (pid = waitpid(-1,&status,WNOHANG)) > 0) Sono possibili problemi derivati da questa implementazione? >> Ultima modifica di nalsk : 02-07-2010 alle 19:04. |
|
|
|
|
|
#4 | |
|
Senior Member
Iscritto dal: Apr 2010
Città: Frosinone
Messaggi: 416
|
Quote:
Ultima modifica di tuccio` : 03-07-2010 alle 20:45. |
|
|
|
|
|
|
#5 |
|
Member
Iscritto dal: Jun 2009
Messaggi: 38
|
Si hai ragione, in teoria dovrei sfruttare il meno possibile le pipes, ed è vero che mi sono complicato la vita. Sono alle prime armi con la programmazione di sistema utilizzando processi e pipes.. Però secondo me di logica dovrebbe essere buono! Cioè ok utilizzare wait e/o waitpid, però dal momento che il processo figlio scrive sulla pipe significa che l'istruzione successiva sarà per forza di cose una exit.. Quindi appena il read del padre può leggere dalla pipe è scontato che l'id letto si sia liberato e che debba essere riempito con un nuovo processo.. Mettendo il caso che il processo in exit non sia stato ancora terminato dopo aver scritto, il padre lo esclude lo stesso dalla lista degli id e poi si arrangerà il figlio a terminarsi in pace.. Non ci vedo l'errore ecco tutto..
|
|
|
|
|
|
#6 | |
|
Senior Member
Iscritto dal: Apr 2010
Città: Frosinone
Messaggi: 416
|
Quote:
Ultima modifica di tuccio` : 04-07-2010 alle 10:46. |
|
|
|
|
|
|
#7 | |
|
Senior Member
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
|
Quote:
Sbagliato per le motivazioni portate da tuccio, inutile perche' ci sono gia' le funzioni del sistema per fare quello che serve a te. Secondo me elimina le pipe, non ti servono a niente. Fatto questo hai due strade: la prima e' quella di installare un signal handler (come hai gia' fatto), li' verificare il pid del processo che e' finito e farlo ripartire. La seconda e' quella di fare la wait direttamente nella funzione principale (avendo cura di verificare che la wait e' stata attivata perche' e' morto il figlio non per altri motivi).
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele |
|
|
|
|
|
|
#8 |
|
Member
Iscritto dal: Jun 2009
Messaggi: 38
|
Grazie mille per le delucidazioni ragazzi
|
|
|
|
|
|
#9 |
|
Member
Iscritto dal: Jun 2009
Messaggi: 38
|
Oggi progetto alla mano, ho modificato secondo i vostri consigli in questo modo:
padre Codice:
void ghostkeeper (void) {
my_pid = getpid();
close(pipe_pids[0]);
write(pipe_pids[1],&my_pid,sizeof(my_pid));
pid_t death_PID;
int status;
int i;
for(i=0;i<4;i++) {
if(pid_ghost[i]=fork() == 0) ghost(i);
}
while(1) {
// death_PID = waitpid(WAIT_ANY,&status,0);
death_PID = wait(&status);
for(i=0;i<4;i++) {
if(pid_ghost[i] == death_PID) {
if(pid_ghost[i]=fork() == 0) ghost(i);
}
}
sleep(1);
}
}
Codice:
void ghost (int id) {
int x = 0;
while(x++ < 4+(4*id)) sleep(1);
exit(0);
}
Il programma funziona discretamente se non fosse che la wait sicuramente non mi ritorna il pid, anche se il figlio termina in modo pulito con una exit(0). Ho provato con entrambi i metodi, sia la wait che la waitpid che vedete commentata (che tra l'altro dovrebbero essere equivalenti usate in quel modo), ed in ogni caso non è vera la if(ghost_pid[i] == death_PID). Evidentemente mi viene restituito un errore o comunque qualcosa che non è l'id del figlio. Sicuramente voi esperti vi metterete a ridere ma non saprei che fare.. ho provato anche con diverse exit e nel gapil non trovo la risposta..
|
|
|
|
|
|
#10 | ||
|
Senior Member
Iscritto dal: Apr 2010
Città: Frosinone
Messaggi: 416
|
Quote:
Quote:
Codice:
do {
death_PID = wait(&status);
} while (death_PID < 0);
for ...
|
||
|
|
|
|
|
#11 | |
|
Senior Member
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
|
Quote:
In ogni caso fai attenzione a come controlli il risultato della fork: quando il risultato e' 0 (sei nel processo figlio), non solo devi eseguire ghost() (o quello che vuoi fargli eseguire) ma stare attento che finita la sua esecuzione questo non prosegua a fare quello che fa il padre. Immagino che all'interno di ghost() ci sia uan exit(), sarebbe comunque buona cosa cautelarsi facendo seguire alla ghost() un bell'exit esplicito. questo potrebbe pure spiegare tutti i vari spawn che avevi all'inizio: Codice:
for(i=0;i<4;i++)
{
if(pid_ghost[i] == death_PID)
{
if(pid_ghost[i]=fork() == 0)
{
ghost(i);
exit(0);
}
}
}
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele |
|
|
|
|
|
|
#12 |
|
Member
Iscritto dal: Jun 2009
Messaggi: 38
|
Si marco avevo pensato ad un problema simile per gli spawn verificati in precedenza..però non essendosi più presentati ho lasciato perdere. Ora per sicurezza farò la exit esplicita
|
|
|
|
|
|
#13 |
|
Member
Iscritto dal: Jun 2009
Messaggi: 38
|
Grazie tuccio, farò anche la gestione degli errori, ma non penso serva a molto..
Se io faccio barbaramente: Codice:
death_PID = wait(&status); if(ghost_pid[i]=fork() == 0) ghost(i); gestendo l'errore avrei sempre lo stesso risultato.. che non si entra nel while(death_PID > 0) .. A me interesserebbe più che altro come fare in modo che la wait dia success e capire da dove ne esca l'errore che mi fa restituire -1 |
|
|
|
|
|
#14 | |
|
Senior Member
Iscritto dal: Apr 2010
Città: Frosinone
Messaggi: 416
|
Quote:
|
|
|
|
|
|
|
#15 |
|
Member
Iscritto dal: Jun 2009
Messaggi: 38
|
Ho aggiunto la gestione degli errori, ed alcune fprintf per vedere un pò ciò che viene o non viene eseguito.
Adesso però il problema sembra un'altro, legato strettamente alle fork. questo è il codice del padre: Codice:
void ghostkeeper (void) {
my_pid = getpid();
close(pipe_pids[0]);
write(pipe_pids[1],&my_pid,sizeof(my_pid));
file_error_output = fopen("/home/znd/Scrivania/LabOS1/pacman_pipes/errors.txt","w");
fprintf(file_error_output,"OK\n");
pid_t death_PID;
int status;
int i;
fprintf(file_error_output,"faccio i primi fantasmi\n");
for(i=0;i<4;i++) {
if(pid_ghost[i]=fork() == 0) {
fprintf(file_error_output,"fatto %d\n",i);
ghost(i);
exit(0);
}
}
fprintf(file_error_output,"finito\n");
while(1) {
// death_PID = waitpid(WAIT_ANY,&status,0);
death_PID = wait(&status);
if(death_PID > 0)
for(i=0;i<4;i++) {
fprintf(file_error_output,"Entro nella for %d\n",i);
if(pid_ghost[i] == death_PID) {
fprintf(file_error_output,"death_PID trovato!\n");
if(pid_ghost[i]=fork() == 0) {
fprintf(file_error_output,"partito il ghost\n");
ghost(i);
exit(0);
}
}
}
else {
*errore = strerror(errno);
fprintf(file_error_output,"Output wait: %d - Errore: %s %d\n",death_PID,errore,errno);
}
sleep(1);
}
}
Codice:
OK faccio i primi fantasmi fatto 0 OK faccio i primi fantasmi fatto 1 OK faccio i primi fantasmi fatto 2 OK faccio i primi fantasmi fatto 3 Vabbè cercherò una soluzione..evidentemente dovrò riguardarmi bene tutta la dinamica dei processi.. |
|
|
|
|
|
#16 | |
|
Senior Member
Iscritto dal: Apr 2010
Città: Frosinone
Messaggi: 416
|
Quote:
poi, aggiungo, mi pare impossibile che non venga eseguita almeno questa riga: Codice:
fprintf(file_error_output,"finito\n"); |
|
|
|
|
|
|
#17 |
|
Member
Iscritto dal: Jun 2009
Messaggi: 38
|
RISOLTO
Ho risolto il problema! Erano semplicemente da gestire meglio le fork. Ho solo reso le chiamate più esplicite di quanto lo erano prima.
Ringrazio tantissimo chi mi ha aiutato, soprattutto tuccio Per correttezza posto il codice funzionante: Codice:
void ghostkeeper (void) {
my_pid = getpid();
close(pipe_pids[0]);
write(pipe_pids[1],&my_pid,sizeof(my_pid));
file_error_output = fopen("errors.txt","w");
int i;
for(i=0;i<4;i++) {
pid_ghost[i]=fork();
if(pid_ghost[i] == 0) {
ghost(i);
exit(0);
}
else;
}
while(1) {
// death_PID = waitpid(WAIT_ANY,&status,0);
death_PID = wait(&status);
if(death_PID > 0)
for(i=0;i<4;i++) {
if(pid_ghost[i] == death_PID) {
pid_ghost[i]=fork();
if(pid_ghost[i] == 0) {
ghost(i);
exit(0);
} else;
}
}
else {
*errore = strerror(errno);
fprintf(file_error_output,"Output wait: %d - Errore: %s %d\n",death_PID,errore,errno);
}
sleep(10);
}
}
Ultima modifica di nalsk : 05-07-2010 alle 19:53. |
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 11:52.












ma non saprei che fare.. ho provato anche con diverse exit e nel gapil non trovo la risposta..








