Forum Informatica Unict

LAUREA TRIENNALE (D.M. 270/04) => Sistemi Operativi, 9 CFU => Topic started by: milos224 on 17-07-2012, 15:27:42



Title: Programmazione C: domande
Post by: milos224 on 17-07-2012, 15:27:42
In vista dell'esame ho due domande riguardo la programmazione C:

1) Non ho capito a che serve la chiamata "close()". Se in codice dove ci sono varie printf, inserisco un solo "close(1)" come mai il codice non stampa nessuna print? a cosa serve il close(1)?

2)Numero processi in un codice.
Se io ho il seguente codice
Code:
int main(){
    
    printf("ciao");
    pid_t pid;
    pid = fork();
  
}
quanti processi ho nel codice? Inoltre il main è contato come processo?

3)Come si implementa l'operazione di wait(o signal) su un semaforo in c?


Title: Re:Programmazione C: domande
Post by: ɹǝǝuıƃuǝsɹǝʌǝɹ on 17-07-2012, 15:41:06
1) Non ho capito a che serve la chiamata "close()". Se in codice dove ci sono varie printf, inserisco un solo "close(1)" come mai il codice non stampa nessuna print? a cosa serve il close(1)?
Pre-qequisiti per la comprensione della risposta:
- descrittori di file
- chiamate di sistema (syscall)
- funzione di libreria standard printf
Risposta (http://goo.gl/D7T9w)
Se ti manca almeno un prerequisito, il consiglio è di studiare prima quello. Se li hai tutti, allora la risposta sarà esauriente .smile.

2)Numero processi in un codice.
Se io ho il seguente codice
Code:
int main(){
    
    printf("ciao");
    pid_t pid;
    pid = fork();
  
}
quanti processi ho nel codice? Inoltre il main è contato come processo?
Pre-requisiti per la comprensione della risposta:
- processi
- funzioni
- multi threading su sistemi Unix-like.
La risposta è 2. Il main non è un processo, e non può essere contato come tale.
Risposta lunga (http://goo.gl/iOFO0)


Title: Re:Programmazione C: domande
Post by: milos224 on 17-07-2012, 15:53:38
1) Non ho capito a che serve la chiamata "close()". Se in codice dove ci sono varie printf, inserisco un solo "close(1)" come mai il codice non stampa nessuna print? a cosa serve il close(1)?
Pre-qequisiti per la comprensione della risposta:
- descrittori di file
- chiamate di sistema (syscall)
- funzione di libreria standard printf
Risposta (http://goo.gl/D7T9w)
Se ti manca almeno un prerequisito, il consiglio è di studiare prima quello. Se li hai tutti, allora la risposta sarà esauriente .smile.

2)Numero processi in un codice.
Se io ho il seguente codice
Code:
int main(){
    
    printf("ciao");
    pid_t pid;
    pid = fork();
  
}
quanti processi ho nel codice? Inoltre il main è contato come processo?
Pre-requisiti per la comprensione della risposta:
- processi
- funzioni
- multi threading su sistemi Unix-like.
La risposta è 2. Il main non è un processo, e non può essere contato come tale.
Risposta lunga (http://goo.gl/iOFO0)
Grazie reverse per la risposta!I prerequisiti che dici li ho studiati ma non li ho capiti..

Primo esempio)
Il descrittore di file è un intero non negativo che rappresenta un il canale di input/output. E 1 è lo standard output. Questo vuol dire che in un qualunque codice dove ci sia close(1) non c'è output?
Se io ho il seguente codice
Code:
int main(){
   
    printf("ciao");
    close(1);
    printf("rosso");
   
}
perchè non stampa nulla?

Secondo punto)
La tua risposta è 2. Ma 2 considerando solo la linea della chiamata fork, dato che duplica il processo?


Title: Re:Programmazione C: domande
Post by: ɹǝǝuıƃuǝsɹǝʌǝɹ on 18-07-2012, 01:52:16
perchè non stampa nulla?
Il buffer/file/stream su cui la funzione di libreria printf scrive (e che sversa dentro il descrittore di file numero 1, chiamato anche stdout = standard output), non viene svuotato automaticamente ad ogni invocazione, perciò normalmente in C si aspetta il successivo carattere di ritorno a capo \n (ascii 13 decimale) per farlo.
Se vuoi costringere uno svuotamento del buffer puoi usare la funzione di libreria standard fflush (http://goo.gl/sTI7J) passandole come parametro proprio stdout.

Oppure puoi prependere (accodare) un \n alla fine della stringa passata alla prima invocazione di printf (ma così introduci un "a-capo" cambiando di fatto l'output previsto dalla prima versione del codice).

[...]

Per evitare di dover passare attraverso questi problemi legati alla particolare implementazione delle strutture FILE (*), prova a scrivere direttamente con la syscall write (http://goo.gl/LnYlq) (che non richiede nemmeno che le stringhe, anzi i buffer di byte, da scrivere siano terminate da carattere NULL \0  :-OK), con una scrittura del tipo
Code:
char [] stringa = "ciao";
write (1, stringa, 4);
//oppure
write (1, stringa, strlen (stringa)) //questa invocazione richiede l'inclusione di <string.h>

//questa versione non usa una stringa C (terminata da byte nullo), ma funziona comunque.
//NON vi si può applicare strlen per contarne i caratteri, perché nessuno garantisce che ci sia un byte nullo dopo la 'o'
char [] stringa = {'c', 'i', 'a', 'o'};
write (1, stringa, 4);

Secondo punto)
La tua risposta è 2. Ma 2 considerando solo la linea della chiamata fork, dato che duplica il processo?
Esattamente. Dal momento in cui la chiamata a fork (invocazione) restituisce senza errori, ci sono esattamente due processi identici, tranne per il fatto che uno è genitore (padre) e l'altro figlio.


Title: Re:Programmazione C: domande
Post by: milos224 on 18-07-2012, 08:12:30
perchè non stampa nulla?
Il buffer/file/stream su cui la funzione di libreria printf scrive (e che sversa dentro il descrittore di file numero 1, chiamato anche stdout = standard output), non viene svuotato automaticamente ad ogni invocazione, perciò normalmente in C si aspetta il successivo carattere di ritorno a capo \n (ascii 13 decimale) per farlo.
Se vuoi costringere uno svuotamento del buffer puoi usare la funzione di libreria standard fflush (http://goo.gl/sTI7J) passandole come parametro proprio stdout.

Oppure puoi prependere (accodare) un \n alla fine della stringa passata alla prima invocazione di printf (ma così introduci un "a-capo" cambiando di fatto l'output previsto dalla prima versione del codice).

[...]

Per evitare di dover passare attraverso questi problemi legati alla particolare implementazione delle strutture FILE (*), prova a scrivere direttamente con la syscall write (http://goo.gl/LnYlq) (che non richiede nemmeno che le stringhe, anzi i buffer di byte, da scrivere siano terminate da carattere NULL \0  :-OK), con una scrittura del tipo
Code:
char [] stringa = "ciao";
write (1, stringa, 4);
//oppure
write (1, stringa, strlen (stringa)) //questa invocazione richiede l'inclusione di <string.h>

//questa versione non usa una stringa C (terminata da byte nullo), ma funziona comunque.
//NON vi si può applicare strlen per contarne i caratteri, perché nessuno garantisce che ci sia un byte nullo dopo la 'o'
char [] stringa = {'c', 'i', 'a', 'o'};
write (1, stringa, 4);

Secondo punto)
La tua risposta è 2. Ma 2 considerando solo la linea della chiamata fork, dato che duplica il processo?
Esattamente. Dal momento in cui la chiamata a fork (invocazione) restituisce senza errori, ci sono esattamente due processi identici, tranne per il fatto che uno è genitore (padre) e l'altro figlio.
Perció basta un close(1) per non far stampare nulla, anche se dopo ho altre print?


Title: Re:Programmazione C: domande
Post by: ɹǝǝuıƃuǝsɹǝʌǝɹ on 18-07-2012, 09:27:38
Sì, scusa ieri sera era tardi e non avevo ben letto la domanda.

Non dovrebbe non stampare nulla: almeno il printf invocato precedentemente alla close doveva stamparlo, però siccome il buffer non era stato svuotato sembrava che non avesse stampato nulla.

Comunque, sì, una volta chiuso il descrittore di file, tutte le scritture su di esso non produrranno nulla (se non un errore).


Title: Re:Programmazione C: domande
Post by: milos224 on 18-07-2012, 09:43:16
Sì, scusa ieri sera era tardi e non avevo ben letto la domanda.

Non dovrebbe non stampare nulla: almeno il printf invocato precedentemente alla close doveva stamparlo, però siccome il buffer non era stato svuotato sembrava che non avesse stampato nulla.

Comunque, sì, una volta chiuso il descrittore di file, tutte le scritture su di esso non produrranno nulla (se non un errore).
Grazie ancora per le risposte. Ma per aprire il descrittore invece? open(1) non credo possa andare bene..


Title: Re:Programmazione C: domande
Post by: milos224 on 19-07-2012, 12:02:51
Per implementare l'operazione di wait ( o signal) su un semaforo devo usare la chiamata di sistema "semop"?
Nelle slide del prof questa è la chiamata:
int semop(int semid, struct sembuf *ops, unsigned nops) dove semid è il descrittore del semaforo,ops punta ad un vettore formato da una o più istanze di una struttura standard e nops contiene il numero di elementi del vettore puntato da ops.



Title: Re:Programmazione C: domande
Post by: Chuck_son on 19-07-2012, 21:47:48
Per implementare l'operazione di wait ( o signal) su un semaforo devo usare la chiamata di sistema "semop"?
Nelle slide del prof questa è la chiamata:
int semop(int semid, struct sembuf *ops, unsigned nops) dove semid è il descrittore del semaforo,ops punta ad un vettore formato da una o più istanze di una struttura standard e nops contiene il numero di elementi del vettore puntato da ops.


si esatto, non ci sono chiamate "native" di wait e signal


Title: Re:Programmazione C: domande
Post by: milos224 on 20-07-2012, 13:38:33
Ritorno sugli argomenti con 2 domande:
1) Per quanto riguarda la domanda sulla close(1), se ho capito bene il modo per riaprire l'output è open(1).
Questo codice allora perchè non stampa nulla?
Code:
int main(){
   
    printf("ciao");
    close(1);
    open(1);
    printf("eii");
    printf("rosso");
   
}

2)Domanda sulla fork().
Questo codice
Code:
int main(){
   
    printf("ciao");
    pid_t pid; pid_t pid2;
    pid = fork();
    pid2=fork();
}
ha 3 processi?


Title: Re:Programmazione C: domande
Post by: ɹǝǝuıƃuǝsɹǝʌǝɹ on 20-07-2012, 14:20:55
1) Per quanto riguarda la domanda sulla close(1), se ho capito bene il modo per riaprire l'output è open(1).
Questo codice allora perchè non stampa nulla?
Code:
int main(){
   
    printf("ciao");
    close(1);
    open(1);
    printf("eii");
    printf("rosso");
   
}
A meno che tu non abbia creato una tua funzione personale che si chiama proprio open, quel codice non compila.
Sinceramente non ricordo come fare a riaprire lo standard output una volta chiuso, ma di certo bisogna specificare un qualche tipo di PATH nella sintassi di open. .penso

Questo codice
Code:
int main(){
   
    printf("ciao");
    pid_t pid; pid_t pid2;
    pid = fork();
    pid2=fork();
}
ha 3 processi?
Sì.


Title: Re:Programmazione C: domande
Post by: milos224 on 20-07-2012, 14:29:03
1) Per quanto riguarda la domanda sulla close(1), se ho capito bene il modo per riaprire l'output è open(1).
Questo codice allora perchè non stampa nulla?
Code:
int main(){
    
    printf("ciao");
    close(1);
    open(1);
    printf("eii");
    printf("rosso");
    
}
A meno che tu non abbia creato una tua funzione personale che si chiama proprio open, quel codice non compila.
Sinceramente non ricordo come fare a riaprire lo standard output una volta chiuso, ma di certo bisogna specificare un qualche tipo di PATH nella sintassi di open. .penso

Questo codice
Code:
int main(){
    
    printf("ciao");
    pid_t pid; pid_t pid2;
    pid = fork();
    pid2=fork();
}
ha 3 processi?
Sì.
Reverse quel codice a me compila, cioè errori non me ne da e non ho creato nulla. Non stampa nulla però.

Riguardo inoltre la seconda domanda: ho 3 processi, che sono dati due dalla fork e uno dal processo del metodo stesso? Cioè le due fork duplicano lo stesso processo?


Title: Re:Programmazione C: domande
Post by: Sickboy on 20-07-2012, 22:50:57
La chiamata fork() non fa altro che duplicare un processo. Dopo tale chiamata , se avvenuta con successo, vengono generati due processi, il processo padre e il processo figlio.
Quindi ad ogni fork() sono generati 2 processi.   :-ciao


Title: Re:Programmazione C: domande
Post by: ɹǝǝuıƃuǝsɹǝʌǝɹ on 20-07-2012, 23:28:01
Reverse quel codice a me compila, cioè errori non me ne da e non ho creato nulla. Non stampa nulla però.
Prova a compilare con -Wall -Werror e scoprirai almeno 3 cose che non vanno bene (tutte della stessa natura).

Riguardo inoltre la seconda domanda: ho 3 processi, che sono dati due dalla fork e uno dal processo del metodo stesso? Cioè le due fork duplicano lo stesso processo?
La chiamata fork() non fa altro che duplicare un processo. Dopo tale chiamata , se avvenuta con successo, vengono generati due processi, il processo padre e il processo figlio.
Quindi ad ogni fork() sono generati 2 processi.   :-ciao
In realtà il processo generato è solo uno (il figlio), l'altro (il padre) esisteva già e mantiene il PID che aveva prima della invocazione a fork.
Quindi è un padre che genera due figli, che potremmo dire essere inconsciamente fratelli :boh.


Title: Re:Programmazione C: domande
Post by: milos224 on 21-07-2012, 00:02:55
Reverse quel codice a me compila, cioè errori non me ne da e non ho creato nulla. Non stampa nulla però.
Prova a compilare con -Wall -Werror e scoprirai almeno 3 cose che non vanno bene (tutte della stessa natura).
Ma esiste un modo per "riaprire" l'output?
Riguardo inoltre la seconda domanda: ho 3 processi, che sono dati due dalla fork e uno dal processo del metodo stesso? Cioè le due fork duplicano lo stesso processo?
La chiamata fork() non fa altro che duplicare un processo. Dopo tale chiamata , se avvenuta con successo, vengono generati due processi, il processo padre e il processo figlio.
Quindi ad ogni fork() sono generati 2 processi.   :-ciao
In realtà il processo generato è solo uno (il figlio), l'altro (il padre) esisteva già e mantiene il PID che aveva prima della invocazione a fork.
Quindi è un padre che genera due figli, che potremmo dire essere inconsciamente fratelli :boh.
Si, infatti. In questo caso il processo che viene duplicato è il processo stesso dentro il main? Se noi scriviamo 20 fork, tutte dentro lo stesso metodo, i processi saranno 21 giusto?


Title: Re:Programmazione C: domande
Post by: Daréios89 on 21-07-2012, 13:21:08
Quote
Quindi ad ogni fork() sono generati 2 processi.

E quindi perchè i processi sono 3? Dato che abbiamo due fork() non dovrebbero essere 4?


Title: Re:Programmazione C: domande
Post by: ɹǝǝuıƃuǝsɹǝʌǝɹ on 21-07-2012, 14:46:38
Quote
Quindi ad ogni fork() sono generati 2 processi.

E quindi perchè i processi sono 3? Dato che abbiamo due fork() non dovrebbero essere 4?
Se leggi bene nei miei interventi precedenti, vedrai che ho risposto puntualmente a quella domanda, correggendone l'affermazione.

Leggere per credere...
La chiamata fork() non fa altro che duplicare un processo. Dopo tale chiamata , se avvenuta con successo, vengono generati due processi, il processo padre e il processo figlio.
Quindi ad ogni fork() sono generati 2 processi.   :-ciao
In realtà il processo generato è solo uno (il figlio), l'altro (il padre) esisteva già e mantiene il PID che aveva prima della invocazione a fork.


Title: Re:Programmazione C: domande
Post by: Daréios89 on 21-07-2012, 14:51:53
Premetto che sto ripassando altro e che la parte di laboratorio la devo vedere domani....però:

Code:
int main(){
   
    printf("ciao");
    pid_t pid; pid_t pid2;
    pid = fork();
    pid2=fork();
}

Qual è la dinamica? Cioè c' è il padre che genera il primo figlio, PID, e poi lo stesso padre genera PID2? Come faccio a capire che hanno lo stesso padre quei due processi?


Title: Re:Programmazione C: domande
Post by: milos224 on 21-07-2012, 15:08:13
Premetto che sto ripassando altro e che la parte di laboratorio la devo vedere domani....però:

Code:
int main(){
   
    printf("ciao");
    pid_t pid; pid_t pid2;
    pid = fork();
    pid2=fork();
}

Qual è la dinamica? Cioè c' è il padre che genera il primo figlio, PID, e poi lo stesso padre genera PID2? Come faccio a capire che hanno lo stesso padre quei due processi?
Se non ho capito male, pid e pid2 duplicano lo stesso processo, ovvero il processo stesso contenuto dentro il main. In teoria hanno lo stesso padre.
Ma prendi l'informazione con le pinze, non so se è giusta.


Title: Re:Programmazione C: domande
Post by: Chuck_son on 21-07-2012, 16:18:52

Se non ho capito male, pid e pid2 duplicano lo stesso processo, ovvero il processo stesso contenuto dentro il main. In teoria hanno lo stesso padre.
Ma prendi l'informazione con le pinze, non so se è giusta.

si è cosi... guarda il file multiforkwait.c per rendertene conto


Title: Re:Programmazione C: domande
Post by: milos224 on 21-07-2012, 19:23:13

Se non ho capito male, pid e pid2 duplicano lo stesso processo, ovvero il processo stesso contenuto dentro il main. In teoria hanno lo stesso padre.
Ma prendi l'informazione con le pinze, non so se è giusta.

si è cosi... guarda il file multiforkwait.c per rendertene conto
chuck per la chiamata close(1) che mi sai dire? basta quella in un qualsiasi codice per non far stampare nesusna print? non c'è modo di riaprire l'output?


Title: Re:Programmazione C: domande
Post by: Daréios89 on 21-07-2012, 20:01:41
E il processo contenuto nel main qual è?


Title: Re:Programmazione C: domande
Post by: ɹǝǝuıƃuǝsɹǝʌǝɹ on 21-07-2012, 22:08:22
non c'è modo di riaprire l'output?
Sinceramente non lo so :boh, ma direi di non preoccuparti (almeno per adesso) giacché questo livello di conoscenze è eccessivamente approfondito per quello che ti serve sapere da questa materia .smile.

E il processo contenuto nel main qual è?
Questa domanda non ha senso. "main" è una funzione. Le funzioni non contengono processi, semmai il contrario (e sarebbe anche un abuso di terminologia dirlo).


Title: Re:Programmazione C: domande
Post by: Daréios89 on 21-07-2012, 22:30:27
Quote
Questa domanda non ha senso. "main" è una funzione. Le funzioni non contengono processi

Appunto!!!

Quindi io vedo pid e pid2, come due processi....quando è fatta la fork() non sono loro rispettivamente i padri che duplicano se stessi?


Title: Re:Programmazione C: domande
Post by: Sickboy on 22-07-2012, 12:13:23
Guardate l'esempio multifork nelle dispense del prof, testatelo così capite meglio cosa accade al momento delle chiamate fork.


Title: Re:Programmazione C: domande
Post by: milos224 on 22-07-2012, 13:08:32
Guardate l'esempio multifork nelle dispense del prof, testatelo così capite meglio cosa accade al momento delle chiamate fork.
io non ci ho capito molto..
Code:
#include <stdio.h>
#include <stdlib.h>
int main() {
pid_t pid;
int i;
pid = fork(); // creo un primo figlio
if (pid == 0) {
// processo figlio 1
for (i=0; i<20; i++) {
sleep(rand()%2);
printf("Sono il FIGLIO 1.\n"); }
exit(0);
}
pid = fork(); // creo un secondo figlio
if (pid == 0) {
// processo figlio 2
for (i=0; i<20; i++) {
sleep(rand()%2);
printf("Sono il FIGLIO 2.\n"); }
exit(0);
}
// processo padre
for (i=0; i<20; i++) {
sleep(rand()%2);
printf("Sono il PADRE.\n"); }
exit(0);
}
exit(0) chiude il processo che ha il pid uguale a 0?

inoltre approfitto per fare una domanda sulla close.. se in questo codice fuori da un ciclo scrivo close(1) vuol dire che chiude l'output del processo che ha pid 1? come faccio a chiudere l'output del primo figlio?


Title: Re:Programmazione C: domande
Post by: Sickboy on 22-07-2012, 13:53:35
Guardate l'esempio multifork nelle dispense del prof, testatelo così capite meglio cosa accade al momento delle chiamate fork.
io non ci ho capito molto..
Code:
#include <stdio.h>
#include <stdlib.h>
int main() {
pid_t pid;
int i;
pid = fork(); // creo un primo figlio
if (pid == 0) {
// processo figlio 1
for (i=0; i<20; i++) {
sleep(rand()%2);
printf("Sono il FIGLIO 1.\n"); }
exit(0);
}
pid = fork(); // creo un secondo figlio
if (pid == 0) {
// processo figlio 2
for (i=0; i<20; i++) {
sleep(rand()%2);
printf("Sono il FIGLIO 2.\n"); }
exit(0);
}
// processo padre
for (i=0; i<20; i++) {
sleep(rand()%2);
printf("Sono il PADRE.\n"); }
exit(0);
}
exit(0) chiude il processo che ha il pid uguale a 0?

la funzione exit prevede un parametro attraverso il quale il processo che termina comunica al padre informazioni sul suo stato di terminazione. exit(0) indica lo stato di corretta terminazione. exit(-1) indica la terminazione con errore.

http://www.gnu.org/software/libc/manual/html_node/Exit-Status.html


Title: Re:Programmazione C: domande
Post by: Chuck_son on 22-07-2012, 14:03:48
.cominciamo dal fatto che pid 0 è il processo INIT ...... il pid 0 viene restituito da fork() al figlio.. al padre viene restituito il pid del figlio creato... il pid del padre si ottiene dal processo figlio tramite getppid()


Title: Re:Programmazione C: domande
Post by: Sickboy on 22-07-2012, 14:15:49
Guardate l'esempio multifork nelle dispense del prof, testatelo così capite meglio cosa accade al momento delle chiamate fork.
inoltre approfitto per fare una domanda sulla close.. se in questo codice fuori da un ciclo scrivo close(1) vuol dire che chiude l'output del processo che ha pid 1? come faccio a chiudere l'output del primo figlio?
La chiamata int close(int fd) serve per chiudere un fi le, libera il descrittore del file fd e la relativa voce nella tabella dei file aperti.

http://www.dmi.unict.it/diraimondo/uploads/classes/so/1011/SO-lab-unix-programming-video.pdf


Title: Re:Programmazione C: domande
Post by: milos224 on 22-07-2012, 14:52:27
Guardate l'esempio multifork nelle dispense del prof, testatelo così capite meglio cosa accade al momento delle chiamate fork.
inoltre approfitto per fare una domanda sulla close.. se in questo codice fuori da un ciclo scrivo close(1) vuol dire che chiude l'output del processo che ha pid 1? come faccio a chiudere l'output del primo figlio?
La chiamata int close(int fd) serve per chiudere un fi le, libera il descrittore del file fd e la relativa voce nella tabella dei file aperti.

http://www.dmi.unict.it/diraimondo/uploads/classes/so/1011/SO-lab-unix-programming-video.pdf
Si ma come mai
Code:
int main(){
printf("ciao");
close(1);
printf("rosso");
}
non stampa nulla? cosa si deve fare per far stampare rosso, senza togliere il close?


Title: Re:Programmazione C: domande
Post by: GenteGuasta on 22-07-2012, 15:46:12
in un sistema Unix c'è un descrittore di file “speciali”: stdin, stdout e stderr identificati rispettivamente dai valori 0, 1 e 2. Con close(1) non puoi più redirigere il traffico verso lo stdout e quindi non ti stamperà mai "rosso". L'unico modo per farti stampare "rosso" credo sia togliere il close(1), oppure redirigere il traffico verso un file esterno e di conseguenza leggerlo.


Title: Re:Programmazione C: domande
Post by: milos224 on 22-07-2012, 15:51:49
in un sistema Unix c'è un descrittore di file “speciali”: stdin, stdout e stderr identificati rispettivamente dai valori 0, 1 e 2. Chiudendo lo stdout non puoi più redirigere il traffico verso lo stdout e quindi non ti stamperà mai "rosso". L'unico modo per farti stampare "rosso" credo sia togliere il close(1), oppure redirigere il traffico verso un file esterno e di conseguenza leggerlo.

Ok ma come mai nell'esempio del prof
Code:
#include <stdio.h>
#include <stdlib.h>
int main() {
pid_t pid;
int i;
pid = fork(); // creo un primo figlio
if (pid == 0) {
// processo figlio 1
for (i=0; i<20; i++) {
sleep(rand()%2);
printf("Sono il FIGLIO 1.\n"); }
exit(0);
}

close(1);

pid = fork(); // creo un secondo figlio
if (pid == 0) {
// processo figlio 2
for (i=0; i<20; i++) {
sleep(rand()%2);
printf("Sono il FIGLIO 2.\n"); }
exit(0);
}
// processo padre
for (i=0; i<20; i++) {
sleep(rand()%2);
printf("Sono il PADRE.\n"); }
exit(0);
}
se io metto close(1) a caso nel codice (fuori di ogni ciclo) stampa praticamente il processo figlio 1? non dovrebbe non stampare nulla?


Title: Re:Programmazione C: domande
Post by: GenteGuasta on 22-07-2012, 15:59:27
Se ti riferisci al file "multifork.c" credo che col tanto parlare di close(1) ti sia comparso per non so quale oscura ragione..oppure può essere che col caldo io stia perdendo colpi 8-| ...cmq ho appena visto il codice dell'esempio e quel close(1) non è presente:

Code:
#include <stdio.h>
#include <stdlib.h>
int main() {
pid_t pid;
int i;
pid = fork(); // creo un primo figlio
if (pid == 0) {
// processo figlio 1
for (i=0; i<20; i++) {
sleep(rand()%2);
printf("Sono il FIGLIO 1.\n"); }
exit(0);
}
pid = fork(); // creo un secondo figlio
if (pid == 0) {
// processo figlio 2
for (i=0; i<20; i++) {
sleep(rand()%2);
printf("Sono il FIGLIO 2.\n"); }
exit(0);
}
// processo padre
for (i=0; i<20; i++) {
sleep(rand()%2);
printf("Sono il PADRE.\n"); }
exit(0);
}


Title: Re:Programmazione C: domande
Post by: milos224 on 22-07-2012, 16:03:49
Se ti riferisci al file "multifork.c" credo che col tanto parlare di close(1) ti sia comparso per non so quale oscura ragione..oppure può essere che col caldo io stia perdendo colpi 8-| ...cmq ho appena visto il codice dell'esempio e quel close(1) non è presente:

Code:
#include <stdio.h>
#include <stdlib.h>
int main() {
pid_t pid;
int i;
pid = fork(); // creo un primo figlio
if (pid == 0) {
// processo figlio 1
for (i=0; i<20; i++) {
sleep(rand()%2);
printf("Sono il FIGLIO 1.\n"); }
exit(0);
}
pid = fork(); // creo un secondo figlio
if (pid == 0) {
// processo figlio 2
for (i=0; i<20; i++) {
sleep(rand()%2);
printf("Sono il FIGLIO 2.\n"); }
exit(0);
}
// processo padre
for (i=0; i<20; i++) {
sleep(rand()%2);
printf("Sono il PADRE.\n"); }
exit(0);
}
infatti tranquillo non è il caldo l'ho aggiunto io!  :nono
volevo sapere perchè in questo caso stampa solo il processo figlio 1, se close(1) non fa stampare nulla?


Title: Re:Programmazione C: domande
Post by: Sickboy on 22-07-2012, 16:20:57
.cominciamo dal fatto che pid 0 è il processo INIT ...... il pid 0 viene restituito da fork() al figlio.. al padre viene restituito il pid del figlio creato... il pid del padre si ottiene dal processo figlio tramite getppid()
Date un occhiata qui in caso per altri chiarimenti  :-ciao

http://www.gnu.org/software/libc/manual/html_node/Creating-a-Process.html#Creating-a-Process



Title: Re:Programmazione C: domande
Post by: ɹǝǝuıƃuǝsɹǝʌǝɹ on 22-07-2012, 17:28:39
Si ma come mai
Code:
int main(){
printf("ciao");
close(1);
printf("rosso");
}
non stampa nulla? cosa si deve fare per far stampare rosso, senza togliere il close?
Allora, ci sono diverse correnti di pensiero su cosa fare se non vuoi togliere il close(1).
Una via è di duplicare in precedenza il descrittore del file con dup, poi usare close(1) e poi riduplicare il descrittore precedentemente duplicato con dup2 (in cui, diversamente da dup, puoi specificare anche quale vecchio descrittore riciclare, nel tuo caso 1).

In caso, consiglio la lettura di questa strana discussione (http://goo.gl/RMGKQ), dove il problema viene trattato da esperti (più esperti di me).

in un sistema Unix c'è un descrittore di file "speciali": stdin, stdout e stderr identificati rispettivamente dai valori 0, 1 e 2. Con close(1) non puoi più redirigere il traffico verso lo stdout e quindi non ti stamperà mai "rosso". L'unico modo per farti stampare "rosso" credo sia togliere il close(1), oppure redirigere il traffico verso un file esterno e di conseguenza leggerlo.
Sempre nella discussione precedente, c'è qualcuno che si è inventato dei modi per farlo. Ad esempio:
Code:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main (void)
{
    printf ("stampa prima di close (1)\n");
    fflush (stdout); //obbligatorio nonostante lo \n alla fine della printf precedente
                            //per costringere la fuoriuscita dei dati sul file nel file system

    close (1);

    int fd = open("/dev/tty", O_WRONLY | O_APPEND);
    stdout = fdopen(fd, "w");

    fprintf (stderr, "fd = %d\n", fd);
    
    char buffer [] = "prova di scrittura su(l nuovo) stdout: MI VEDI?\n";
    printf ("%s", buffer);

    return 0;
}
In questo caso vedrai tutto l'output (anche quello stampato dalla normalissima printf successiva a close (1), sulla console.
Infatti cosa avviene? ($$ è il PID della console bash corrente)
Normalmente /proc/$(pidof prog)/fd/1 è un link simbolico a un file del tipo /dev/pts/0 e poi:
1) supposto che la shell abbia /proc/$$/fd/1 come link simbolico a /dev/ttyS0
il programma viene avviato con /proc/$(pidof prog)/fd/1 anch'esso come link simbolico a /dev/ttyS0
2) una volta che il descrittore di file 1 viene chiuso in prog, l'apertura sempre di /dev/ttyS0 restituisce un descrittore di file nuovo (che casualmente è sempre 1, ma potrebbe essere più alto), e capita come segue:
3a) se il descrittore nuovo è sempre 1, allora vedrai ancora l'output sulla shell
3b) se il descrittore nuovo è diverso da 1 (e da 2, ma 2 non è stato chiuso quindi non potrà essere 2), allora non vedrai l'output sulla shell, ma andrà a finire dovunque punti tale descrittore...

in un sistema Unix c'è un descrittore di file “speciali”: stdin, stdout e stderr identificati rispettivamente dai valori 0, 1 e 2. Chiudendo lo stdout non puoi più redirigere il traffico verso lo stdout e quindi non ti stamperà mai "rosso". L'unico modo per farti stampare "rosso" credo sia togliere il close(1), oppure redirigere il traffico verso un file esterno e di conseguenza leggerlo.
Ok ma come mai nell'esempio del prof
Code:
//omissis
se io metto close(1) a caso nel codice (fuori di ogni ciclo) stampa praticamente il processo figlio 1? non dovrebbe non stampare nulla?
No. Perchè tu hai messo close(1) dopo la fork (), e se guardi il man di fork scoprirai che fork duplica tutte le risorse (compresi i descrittori di file) del padre anche nel figlio.
Ciò significa che ci sono due descrittori 1 in gioco (come sarebbe in generale per 2 processi distinti), solo che stavolta entrambi i descrittori puntano allo stesso file (la console /dev/ttyqualcosa). Chiudere 1 nel primo (cioè eliminare il link simbolico di /proc/$PID_PADRE/fd/1 a /dev/ttyqualcosa) non elimina anche il link simbolico di /proc/$PID_FIGLIO/fd/1 a /dev/ttystessa_qualcosa_del_padre), quindi il figlio stamperà serenamente su schermo, mentre il padre non più.

Diverso è il caso in cui sta avvenendo del redirezionamento.

Ad esempio, se il tuo programma si chiamasse prog e tu invocassi l'esecuzione di
./prog > output
Allora nel file "output" vedresti il contenuto solo della prima printf.
Quello della seconda non è più valido, perché in quel codice hai aperto un file (/dev/tty) che è bensì legato (come /dev/ttyS0) alla shell corrente, ma non è più collegato (stile "a cascata") al vero file che è presente nel file system e che è collegato a
/proc/$(pidof prog)/fd/1.
Infatti cosa avviene?
1) supposto che la shell abbia /proc/$$/fd/1 come link simbolico a /dev/ttyS0
il programma viene avviato con /proc/$(pidof prog)/fd/1 linkato simbolicamente a (ad esempio) /home/utente/output
2) la prima printf stamperà correttamente (ma solo se si è fatto fflush (stdout) PRIMA di close(1)) la prima stringa nel file output.
3) una volta che il descrittore di file 1 viene chiuso in prog, l'apertura sempre di /dev/ttyS0 restituisce un descrittore di file nuovo (che casualmente è sempre 1, ma potrebbe essere più alto), e capita come segue:
3a) se il descrittore nuovo è sempre 1, allora vedrai ancora l'output sulla shell (ma non dentro il file output)
3b) se il descrittore nuovo è diverso da 1 (e da 2, ma 2 non è stato chiuso quindi non potrà essere 2), allora non vedrai l'output sulla shell, e nemmeno nel file output, ma andrà a finire dovunque punti il descrittore 2...

Quindi, riassumendo, la cosa migliore per fare close(1) e poi poter riaprire è la seguente:
1) chiamare getpid per conoscere il PID del processo, sia esso $PID.
2) verificare a quale file fisico punta il link simbolico /proc/$PID/fd/1. Sia il path di tale file $PATHFD1
3) fare close(1)
4) aprire con open il file $PATHFD1. sia $FD il descrittore restituito da questa apertura con open
5) usare dup2 per clonare $FD su 1 (chiudendo qualsiasi altro descrittore precedentemente aperto 1)
6) nel caso in cui sia stato chiuso anche stdout (con fclose(stdout)) assicurarsi, se il compilatore lo permette, cioè se stdout è (almeno una macro che punta ad) un L-value (cioè valore assegnabile), di riaprire il FILE* stdout re-linkandolo al descrittore 1 (e questo si può fare con una istruzione stdout = fdopen (1, "w")).

Wow.

Grazie per questa discussione. Prima non avevo idea di come si dovessero fare queste cose, ma non saper rispondere mi ha costretto (per amore di conoscenza) a documentarmi per conto mio e capire queste cose nuove (che al tempo del corso di Lab. di Sistemi Operativi [Open Source]) sinceramente non ricordo se ci avevano spiegato (ad es il link dei vari descrittori ai file /proc/$PID/fd/1, 2, 3).


Title: Re:Programmazione C: domande
Post by: milos224 on 22-07-2012, 17:43:35
[...]
Come mai però stampa solo il primo figlio mentre il secondo no?

EDIT: quote del mio messaggio rimosso perché veramente TROOOOOPPO lungo :boh


Title: Re:Programmazione C: domande
Post by: ɹǝǝuıƃuǝsɹǝʌǝɹ on 22-07-2012, 19:40:26
[...]
Come mai però stampa solo il primo figlio mentre il secondo no?

EDIT: quote del mio messaggio rimosso perché veramente TROOOOOPPO lungo :boh
Banale, se hai inteso cosa avviene grazie al mio messaggio precedente.

Guarda il codice:
Code:
int main() {
pid = fork(); // creo un primo figlio
    //[omissis]
    close(1);

    pid = fork(); // creo un secondo figlio
    //[omissis]
}
Il primo figlio eredita tre descrittori APERTI [1, 2, 3] (perciò ha anche i suoi aperti, che poi risultano indipendenti da quello che accade DOPO la fork a quelli del padre), mentre il secondo figlio viene generato DOPO la close (1) e, quindi, eredita due descrittori APERTI [2, 3] e uno chiuso (libero, non più usabile), e quello chiuso è proprio [1], quindi lui soffre dello stesso problema del padre. :boh


Title: Re:Programmazione C: domande
Post by: milos224 on 22-07-2012, 23:37:23
[...]
Come mai però stampa solo il primo figlio mentre il secondo no?

EDIT: quote del mio messaggio rimosso perché veramente TROOOOOPPO lungo :boh
Banale, se hai inteso cosa avviene grazie al mio messaggio precedente.

Guarda il codice:
Code:
int main() {
pid = fork(); // creo un primo figlio
    //[omissis]
    close(1);

    pid = fork(); // creo un secondo figlio
    //[omissis]
}
Il primo figlio eredita tre descrittori APERTI [1, 2, 3] (perciò ha anche i suoi aperti, che poi risultano indipendenti da quello che accade DOPO la fork a quelli del padre), mentre il secondo figlio viene generato DOPO la close (1) e, quindi, eredita due descrittori APERTI [2, 3] e uno chiuso (libero, non più usabile), e quello chiuso è proprio [1], quindi lui soffre dello stesso problema del padre. :boh
grazie davvero reverse per il tempo perso a rispondere! ho capito tutto (quasi tutto in realtà, non capisco perchè proprio 3 descrittori, ma non fa nulla!)


Title: Re:Programmazione C: domande
Post by: ɹǝǝuıƃuǝsɹǝʌǝɹ on 23-07-2012, 00:18:17
([...] in realtà, non capisco perchè proprio 3 descrittori, ma non fa nulla!)
Ancora più banale: standard in + standard out + standard error = 3 descrittori (standard, presenti di default cioè).
 :boh


Title: Re:Programmazione C: domande
Post by: milos224 on 23-07-2012, 08:14:28
([...] in realtà, non capisco perchè proprio 3 descrittori, ma non fa nulla!)
Ancora più banale: standard in + standard out + standard error = 3 descrittori (standard, presenti di default cioè).
 :boh
Ahhhhh!  :-)| ancora grazie!