View Full Version : [c] Lettura di ESATTAMENTE un carattere da input
megamello
28-10-2006, 16:04
Premesso che già conosco le funzioni getc e fgetc, il problema che ho è il seguente: voglio creare una specie di menu del tipo [1.Accedi - 2.Esci] ed il programma dovrà reagire in base all'input d 1 o 2 (o altro). il mio problema è il bufer d caratteri della tastiera (credo) in quanto una volta preso un carattere da input il programma si comporta in modo corretto, mentre mettendo in ingresso una stringa (es '111') il programma consuma prima tutto il dato in ingresso prima d proseguire (come da es stampa 3 volte comando1 poi prosegue)
vi do un abbozzo di pseudocodice del realtivo programma (non il codice perchè mi insultereste per la mia programmazione 'ad occhio'):
printf('[1.Accedi - 2.Esci]');
comando=fgetc(stdin); //provato anche fgets da 1 char e READ da 1 byte
while (comando !=2){ //confronti fra stringhe implementati tramite strncmp
//poi tramite confronti diretti visto che strnp andava
// in segmentation fault
if (comando=1) printf('comando1');
printf('[1.Accedi - 2.Esci]');
comando=fgetc(stdin);
}
exit(0);
giusto un abbozzo per dare un'idea. come posso implementare la laettura d 1 carattere soltanto, buttendo il resto ( e utilizzando funzioni 'sicure' che mi garantiscono di prendere un numero definito di byte in input)? ho provato mettendo vettori di char d 2 byte , con il primo significativo e sul secondo andavo a scrivere un EOF, ma nn sembrava curarsene + di tanto.
il "comando1" in realtà sarebbe una fork seguita da una exec per un client. già che ci sono vi chiedo anche: se faccio una fork e sul figlio una exec, ilprocesso padre rimanente attivo, come si comportano i programmi? il figlio va sulla stessa shell o su un'altra istanza della shell? posso implementare accesso concorrente con questo metodo (es 2 utenti che utilizzano 2 client diversi generati dallo stesso padre)?
ok mi sono reso conto di essermi espresso malissimo, ma non ho voglia di sistemare, accontentatevi :) (più che altro spero che qualcuno capisca lo stesso così da potermi aiutare)
[ambiente Linux/Unix]
char comando;
...
comando = 0;
while (comando != 2)
{
printf("[1.Accedi - 2.Esci]");
comando = getchar();
/* Pulisco il buffer di input. */
while (getchar() != '\n');
if (isdigit(comando))
{
if (comando == 1)
{
printf("\nComando 1\n\n");
/* Operazioni varie... */
}
}
else
printf("\nComando non valido. Riprovare...\n\n");
}
...
return 0;
il "comando1" in realtà sarebbe una fork seguita da una exec per un client. già che ci sono vi chiedo anche: se faccio una fork e sul figlio una exec, ilprocesso padre rimanente attivo, come si comportano i programmi? il figlio va sulla stessa shell o su un'altra istanza della shell? posso implementare accesso concorrente con questo metodo (es 2 utenti che utilizzano 2 client diversi generati dallo stesso padre)?
Il processo padre rimane attivo, mentre il processo figlio sostituisce (nel caso della famiglia di funzioni exec()) l'immagine del suo processo con quella del processo specificato nella exec(). Quindi il processo figlio diventa "indipendente" dal processo padre, per quanto, essendo il pid del figlio sempre lo stesso, il padre può ad esempio fare una wait() per attendere il figlio, ecc.
EDIT: Per quanto riguarda la fork() (peraliamo quindi di unix/linux/e simili) prova questo semplice programma:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int pid, status;
if ((pid = fork()) == 0)
{
/* Sono il figlio. */
printf("Sono il figlio: pid %d\n\n", getpid());
execl("/bin/ls", "ls" "-l", "-a", (char *) 0);
/* Prova a mettere del codice qui sotto... */
}
else
{
/* Sono il padre. */
printf("Sono il padre: pid %d, pid del figlio %d\nAttendo la terminazione del figlio...\n\n", getpid(), pid);
wait(&status);
printf("Figlio terminato, uscita.\n");
}
return 0;
}
Prova anche a sostituire un altro programma per la execl, magari uno che richiede più tempo di esecuzione, per vedere meglio il comportamento del padre.
megamello
28-10-2006, 18:35
si, so come funzionano fork ed exec, ma mi chiedevo se sulla stessa shell l'esecuzione dei due (amesso che rimangano entrambi attivi) è interlacciata o no, e mi chiedevo anche cosa succederebbe se si facesse partire un nuovo client tramite il processo padre (facendo una nuova fork + exec) mentre già c'è un figlio attivo
si, so come funzionano fork ed exec, ma mi chiedevo se sulla stessa shell l'esecuzione dei due (amesso che rimangano entrambi attivi) è interlacciata o no, e mi chiedevo anche cosa succederebbe se si facesse partire un nuovo client tramite il processo padre (facendo una nuova fork + exec) mentre già c'è un figlio attivo
Cosa intendi per shell interlacciata? Vuoi dire se tutti i processi figli stampano l'output sulla sulla shell del padre?
megamello
28-10-2006, 18:54
si esattamente questo, grazie. devo implementare una lettura e scrittura su memoria condivisa (mem creata dal padre, lettura e scrittura fatte dai figli), com possibilità di concorrenza in lettura/scrittura/cancellazione (da gestire tramite semafori). in pratica quello che mi chiedo è come lanciare + istanze del processo figlio dallo stesso padre (in modo che + figli utilizzino la stessa memoria condivisa) e pensavo d farlo appunto lasciando aperto il padre in atesa di ordini (accedi-esci) ma non so se sarebbe una soluzione valida, oppure se mi converrebbe fare una chiamata shmget in modo non esclusivo e far partire + istanze "padri" ognuna che genera un filgio ed aspetta la terminazione (la mem condiisa creata è unica x tutti i processi così come i semafori o sbaglio?) anche se poi dovrei far sincronizzare i padri in modo chel'ultimo ke si chiude elimini la mem condivisa
si esattamente questo, grazie. devo implementare una lettura e scrittura su memoria condivisa (mem creata dal padre, lettura e scrittura fatte dai figli).
Sì, tutti i processi stampano sulla shell del padre, ma guarda che dopo la execve() (e simili) perdi i puntatori alla memoria condivisa (come si evince dal codice postato prima, dopo una exec non c'è controllo da parte del figlio in caso di successo della exec(), per i motivi descritti prima).
Come descritto anche nella manpage di execve:
RETURN VALUE
If one of the exec functions returns to the calling process image, an error has occurred; the return alue shall be -1, and errno shall be set to indicate the error.
megamello
28-10-2006, 19:02
si so della perdita, infatti la shm attach l'avrei messa sul figlio...cmq leggi il post sopra per favore, che dopo l'edit è diventato un poema :)
grazie di tutto l'aiuto cmq
si so della perdita, infatti la shm attach l'avrei messa sul figlio...cmq leggi il post sopra per favore, che dopo l'edit è diventato un poema :)
Se vuoi che il/i figlio/i del padre siano controllabili anche dopo l'esecuzione di un comando esterno, non usare execve(), bensì system(). La differenza sta nel fatto che la system apre in automatico un nuovo processo e lancia il comando: quando il comando è terminato il controllo ritorn al figlio (che esiste, la sua immagine non è stata sostituita).
In questo modo non hai alcun bisogno di usare memoria condivisa per far dialogare padre e figli: ti basta usare l'exit code del filgio per far capire al padre come è andata.
Nel caso di un solo figlio (come si vede nel mio esempio), tramite la wait(&status) leggi in status il codice di ritorno del figlio (quello passato dalla return del figlio), se invece hai più figli, puoi usare la waitpid() oppure (molto meglio e più facile da gestire) usare una signal() sul segnale SIGCHLD per essere segnalati ogni qual volta un figlio termina (e nella routine di gestione del segnale puoi facilmente sapere il pid del figlio che ha terminato (ed ovviamente il suo exit code).
megamello
28-10-2006, 19:15
il fatto è che DEVO usare una memoria condivisa, in quanto i figli la devono usare come se fosse una bacheca per messaggi... sono fattibili le soluzioni che ho proposto prima?
Ti consiglio di fare come segue:
1) il padre (main) crea la memoria condivisa.
1) il padre crea i figli: tutti i figli ereditano automaticamente una copia del puntatore alla memoria condivisa
3) i figli (e il padre) accedono alla memoria condivisa in mutua esclusione (sezione critica).
4) il padre può controllare in qualunque momento la terminazione dei figli (ed il modo in cui sono terminati) tramite una signal() su SIGCHLD
5) Se i figli devono lanciare nuovi processi esterni, usa la system() invece della execve() (per avere il controllo del figlio anche dopo la terminazione del comando esterno).
megamello
28-10-2006, 19:39
1) il padre crea i figli: tutti i figli ereditano automaticamente una copia del puntatore alla memoria condivisa
è applicabile al creare un figlio in un qualsiasi momento o intendi dire che il padre deve creare tot istanze ed aspettare la terminazione? avrei bisognodi dinamicità in questo, appunto vorrei tenere il padre aperto (e attivo) per far partire una nuova istanza figlio arbitrariamente
è applicabile al creare un figlio in un qualsiasi momento o intendi dire che il padre deve creare tot istanze ed aspettare la terminazione? avrei bisognodi dinamicità in questo, appunto vorrei tenere il padre aperto (e attivo) per far partire una nuova istanza figlio arbitrariamente
Sì sì i figli li lanci quando vuoi, e li tracci con una signal() su SIGCHLD. Non importa quanti figli hai o quando sono stati lanciati, l'importante è avere l'accesso in mutua esclusione alla sezione critica e controllare (da parte del padre) la terminazione dei suoi figli.
EDIT: comunque io uso raramente (anzi direi quasi mai...) la memoria condivisa per far dialogare i processi (devi stare molto attento ad usarla per quanto riguarda la sicurezza), meglio usare pipes + semafori (implementati sempre con una pipe per semplicità) per far dialogare/scambiare dati tra più processi. Poi se ti è stato richiesto esplicitamente di usare la memoria condivisa, oppure ne hai assolutamente bisogno e non sai come fare altrimenti... (ma di solito si trova sempre un'alternativa, anche di uguale/minore complessità implementativa)
megamello
28-10-2006, 21:51
eh si è necessario utilizzare la mem condivisa da richiesta, deve essere usata tipo bacheca dai processi figli...ti rignrazio ancora per l'aiuto che mi hai dato, penso di essere a posto per ora
megamello
05-11-2006, 15:04
scusate ma ho ancora problemi...viposto direttamente il codice poi spiego...
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct {
char userid[10];
char oggetto[20];
char messaggio[100];
} messaggio;
void login(){
char comando;
char stor[2];
int n;
printf("1. Accedi - 2.Esci \n");
comando = fgetc(stdin);
while(fgetc(stdin) != '\n');
if (!isdigit(comando)){printf("Comando non valido. Riprovare.\n 1. Accedi - 2.Esci \n");
comando = fgetc(stdin);
while(fgetc(stdin) != '\n');}
while(comando!='2'){
if (comando=='1') {
//int pid = fork();
//if (pid == -1) puts("Errore nella chiamata fork()");
//if (pid == 0) execl("client", "Client",0);
printf("comando 1 \n");
}
else printf("Comando non valido. Riprovare.");
printf("1. Accedi - 2.Esci \n");
comando = fgetc(stdin);
while(fgetc(stdin) != '\n');
}
exit(1);
}
int main(int argc, char* argv[]){
int ds_shm;
key_t key = 001000;
if ((ds_shm = shmget(key, 20480, IPC_CREAT|0666))<0){
puts("Errore shmget");exit(-3);}
login();
/*CREA SEMAFORI!!!!!*/
}
scusate la mancanza di indentazione.
Allora, il programma (in particolare la funzione login() ) dovrebbe prendere 1 carattere in input e a seconda se sia 1, 2 o altro, dovrebbe stampare comando1, uscire o stampare Comando non valido ( e ciclare). funziona discretamente se non fosse che ha problemi con stringhe di più di un carattere, ossia, se passo stringhe di caratteri casuali in input stampa Comando nonvalido, ma se le stringhe iniziano con 1 o 2 , allora stampa comando1 nel primo caso ed esce nel secondo. come posso fare per evitare ciò?
una domanda....il programma può generare inconsistenza sui dati? c'è pericolo che ciò che passo in ingresso venga memorizzato a partire da char comando e i caratteri seguenti il primo vadano a "sporcare" zone di memoria? utilizzo fgetc per evitare situazioni del genere, ma vorrei avere la certezza....
grazie a tutti per l'aiuto
megamello
07-11-2006, 01:11
*UP*
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.