Pages: 1 2 [3]   Go Down
Print
Author Topic: Programmazione C: domande  (Read 12196 times)
0 Members e 1 Utente non registrato stanno visualizzando questa discussione.
GenteGuasta
Matricola
*
Offline Offline

Posts: 28


« Reply #30 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.
« Last Edit: 22-07-2012, 15:52:25 by GenteGuasta » Logged
milos224
Forumista
***
Offline Offline

Posts: 830


« Reply #31 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?
Logged
GenteGuasta
Matricola
*
Offline Offline

Posts: 28


« Reply #32 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 cool ...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);
}
Logged
milos224
Forumista
***
Offline Offline

Posts: 830


« Reply #33 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 cool ...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?
« Last Edit: 22-07-2012, 16:26:13 by milos224 » Logged
Sickboy
Matricola
*
Offline Offline

Gender: Male
Posts: 41



« Reply #34 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

Logged
ɹǝǝuıƃuǝsɹǝʌǝɹ
Administrator
God of the Forum
*****
Offline Offline

Gender: Male
Posts: 4.474


Più grande è la lotta, e più è glorioso il trionfo


WWW
« Reply #35 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, 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).
« Last Edit: 22-07-2012, 17:30:11 by reversengineer » Logged

La grande marcia della distruzione mentale proseguirà. Tutto verrà negato. Tutto diventerà un credo. È un atteggiamento ragionevole negare l'esistenza delle pietre sulla strada; sarà un dogma religioso affermarla. È una tesi razionale pensare di vivere tutti in un sogno; sarà un esempio di saggezza mistica affermare che siamo tutti svegli. Accenderemo fuochi per testimoniare che due più due fa quattro. Sguaineremo spade per dimostrare che le foglie sono verdi in estate. Non ci resterà quindi che difendere non solo le incredibili virtù e saggezze della vita umana, ma qualcosa di ancora più incredibile: questo immenso, impossibile universo che ci guarda dritto negli occhi. Combatteremo per i prodigi visibili come se fossero invisibili. Guarderemo l'erba e i cieli impossibili con uno strano coraggio. Saremo tra coloro che hanno visto eppure hanno creduto.

In tutto, amare e servire.

  
                            ن                           
I can deal with ads,
I can deal with buffer,
but when ads buffer
I suffer...

...nutrimi, o Signore, "con il pane delle lacrime; dammi, nelle lacrime, copiosa bevanda...

   YouTube 9GAG    anobii  S  Steam T.B.o.I. Wiki [univ] Lezioni private  ʼ  Albo d'Ateneo Unicode 3.0.1
Usa "Search" prima di aprire un post - Scrivi sempre nella sezione giusta - Non spammare - Rispetta gli altri utenti - E ricorda di seguire il Regolamento
milos224
Forumista
***
Offline Offline

Posts: 830


« Reply #36 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
« Last Edit: 22-07-2012, 19:31:49 by reversengineer » Logged
ɹǝǝuıƃuǝsɹǝʌǝɹ
Administrator
God of the Forum
*****
Offline Offline

Gender: Male
Posts: 4.474


Più grande è la lotta, e più è glorioso il trionfo


WWW
« Reply #37 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
Logged

La grande marcia della distruzione mentale proseguirà. Tutto verrà negato. Tutto diventerà un credo. È un atteggiamento ragionevole negare l'esistenza delle pietre sulla strada; sarà un dogma religioso affermarla. È una tesi razionale pensare di vivere tutti in un sogno; sarà un esempio di saggezza mistica affermare che siamo tutti svegli. Accenderemo fuochi per testimoniare che due più due fa quattro. Sguaineremo spade per dimostrare che le foglie sono verdi in estate. Non ci resterà quindi che difendere non solo le incredibili virtù e saggezze della vita umana, ma qualcosa di ancora più incredibile: questo immenso, impossibile universo che ci guarda dritto negli occhi. Combatteremo per i prodigi visibili come se fossero invisibili. Guarderemo l'erba e i cieli impossibili con uno strano coraggio. Saremo tra coloro che hanno visto eppure hanno creduto.

In tutto, amare e servire.

  
                            ن                           
I can deal with ads,
I can deal with buffer,
but when ads buffer
I suffer...

...nutrimi, o Signore, "con il pane delle lacrime; dammi, nelle lacrime, copiosa bevanda...

   YouTube 9GAG    anobii  S  Steam T.B.o.I. Wiki [univ] Lezioni private  ʼ  Albo d'Ateneo Unicode 3.0.1
Usa "Search" prima di aprire un post - Scrivi sempre nella sezione giusta - Non spammare - Rispetta gli altri utenti - E ricorda di seguire il Regolamento
milos224
Forumista
***
Offline Offline

Posts: 830


« Reply #38 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!)
Logged
ɹǝǝuıƃuǝsɹǝʌǝɹ
Administrator
God of the Forum
*****
Offline Offline

Gender: Male
Posts: 4.474


Più grande è la lotta, e più è glorioso il trionfo


WWW
« Reply #39 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
Logged

La grande marcia della distruzione mentale proseguirà. Tutto verrà negato. Tutto diventerà un credo. È un atteggiamento ragionevole negare l'esistenza delle pietre sulla strada; sarà un dogma religioso affermarla. È una tesi razionale pensare di vivere tutti in un sogno; sarà un esempio di saggezza mistica affermare che siamo tutti svegli. Accenderemo fuochi per testimoniare che due più due fa quattro. Sguaineremo spade per dimostrare che le foglie sono verdi in estate. Non ci resterà quindi che difendere non solo le incredibili virtù e saggezze della vita umana, ma qualcosa di ancora più incredibile: questo immenso, impossibile universo che ci guarda dritto negli occhi. Combatteremo per i prodigi visibili come se fossero invisibili. Guarderemo l'erba e i cieli impossibili con uno strano coraggio. Saremo tra coloro che hanno visto eppure hanno creduto.

In tutto, amare e servire.

  
                            ن                           
I can deal with ads,
I can deal with buffer,
but when ads buffer
I suffer...

...nutrimi, o Signore, "con il pane delle lacrime; dammi, nelle lacrime, copiosa bevanda...

   YouTube 9GAG    anobii  S  Steam T.B.o.I. Wiki [univ] Lezioni private  ʼ  Albo d'Ateneo Unicode 3.0.1
Usa "Search" prima di aprire un post - Scrivi sempre nella sezione giusta - Non spammare - Rispetta gli altri utenti - E ricorda di seguire il Regolamento
milos224
Forumista
***
Offline Offline

Posts: 830


« Reply #40 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!  testate ancora grazie!
Logged
Pages: 1 2 [3]   Go Up
Print
Jump to: