Newsgroup: it.comp.lang.c
Titolo: getchar non bloccante

Esiste un modo per controllare l'evento della premuta di un tasto
della tastiera, senza però farlo bloccare?
Una cosa del tipo:
while(1)
{
	x=getcharNONBLOCCANTE();
	if (x==ESC)
		break;
	else
	{
		if (x!=NESSUN TASTO PREMUTO)
			printf("Premuto un tasto diverso da ESC");
		else
			printf("Nessun tasto premuto");
	}
}

 della tastiera, senza però farlo bloccare?
Dipende dall'ambiente che utilizzi:
nel borland per dos esiste kbhit() che
appunto controlla se in coda è stato inserito (quindi premuto)
un tasto.
Ma questo non è ANSI C.


scrisse:

Grazie, purtroppo cercavo qualcosa di standard. Se non esiste, mi puoi
dare una dritta per creare una funzion ad hoc?
Se fosse stato una lettura su file avrei fatto:
open(stdin, O_NONBLOC)
if (read(fileno(stdin),....)==-1)
	if (errno==EAGAIN)
		non ho premuto niente;
ma rimane non posso aprire lo standard input come file, credo.

 
Penso che l'apertura dello stdin non è un problema;
al massimo, usi la dup2 per riaprire uno stream come
stdin, ed il gioco è fatto!

 della tastiera, senza però farlo bloccare?
una select() sullo stdin ??
.... mah !!
;-)))
ciao ...
-- 
#include <stdio.h>
int main(void){char c[]={10,65,110,116,111,110,105,111,32,98,97,114,98,111,110,
101,32,60,104,105,110,100,101,109,105,116,64,116,105,115,99,97,108,105,110,101,
116,46,105,116,62,10,10,0};printf("%s",c);return 0;}

 [...] puoi provare il codice allegato.
Nella gerarchia it.* non sono previsti allegati se non nei ng 
appositi.  Attieniti alle regole, per cortesia.


Taci, idiota e presuntuoso.


 Taci, idiota e presuntuoso.
Taci, idiota e ignorante.

On 11/03/05 10:39, Gioacchino wrote:
Ecco il file che non e` apparso nel post precedente.
#include <stdio.h>
#include <termios.h>            /* per il terminale */
static struct termios orig, new;
static int peek = -1;
int main(void)
{
   int ch = 0;
   /* Prende le impostazioni dello STDIN */
   tcgetattr(0, &orig);
   /* Se guardi `man tcgetattr` scopri tutto, comunque ... */
   new = orig;
   /* Enable canonical mode.  This enables the special characters EOF,
    * EOL,  EOL2,  ERASE,  KILL,  LNEXT, REPRINT, STATUS, and WERASE,
    * and buffers by lines. */
   new.c_lflag &= ~ICANON;
   /* Disabilita l'echo */
   new.c_lflag &= ~ECHO;
   /* Inoltra certi segnali ricevuti */
   new.c_lflag &= ~ISIG;
   /* Cambia i `control chars` */
   new.c_cc[VMIN] = 1;
   new.c_cc[VTIME] = 0;
   tcsetattr(0, TCSANOW, &new);  /* setta i nuovi attributi sul terminale */
   while (ch != 'q') {
         printf("looping\n");
         sleep(1);
         if (kbhit()) {
                 ch = readch();
                 printf("you hit %c\n", ch);
         }
   }
   /* Ripristina */
   tcsetattr(0, TCSANOW, &orig);
   exit(0);
}
int kbhit()
{
   char ch;
   int nread;
   if (peek != -1) return 1;
   new.c_cc[VMIN] = 0;
   tcsetattr(0, TCSANOW, &new);  /* setta attributi  */
   nread = read(0, &ch, 1);      /* legge un char dallo STDIN */
   new.c_cc[VMIN] = 1;           /* restituisce dati dopo aver ricevuto 1
                          * carattere */
   tcsetattr(0, TCSANOW, &new);
   if (nread == 1) {             /* se ha letto un char setta peek  */
         peek = ch;
         return 1;
   }
   return 0;
}
int readch()
{
   /* Si prende il char ricevuto dalla kbhit */
   char ch;
   if (peek != -1) {
         ch = peek;
         peek = -1;
         return ch;
   }
   read(0, &ch, 1);
   return ch;
}
/* */


 Grazie, purtroppo cercavo qualcosa di standard.
Lo standard non lo prevede, anzi prevede che l'input sia 
bufferizzato.  Un'operazione del genere richiede 
un'interfacciamento di basso livello con la periferica di input e 
quindi devi utilizzare un metodo dipendente dal tuo sistema operativo.

 
Ma la select() blocca!
Lui cerca una soluzione che non blocca...

Giovanni
grazie, ora provo


scrisse:

Ho trovato quest'esempio:
#include <stdio.h>
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>
       int
       main(void)
       {
           fd_set rfds;
           struct timeval tv;
           int retval;
           /* Watch stdin (fd 0) to see when it has input. */
           FD_ZERO(&rfds);
           FD_SET(0, &rfds);
           /* Wait up to five seconds. */
           tv.tv_sec = 5;
           tv.tv_usec = 0;
           retval = select(1, &rfds, NULL, NULL, &tv);
           /* Don't rely on the value of tv now! */
           if (retval)
               printf("Data is available now.\n");
               /* FD_ISSET(0, &rfds) will be true */
           else
               printf("No data within five seconds.\n");
           exit(0);
       }

 scrisse:

peccato che non esista in c una funzione simile ad INKEY$ in Visual
Basic...

Giovanni
In pratica a me serve questo perchč stň realizzando un server che
lascia partire un thread ogni connessione al client
il server fa:
while(1)
{
	accept(client)
	pthread_create(client)
}
e quindi vorrei far uscire in modo gradevole il server.
Ho pensato ad un getchar, ma il problema č che quando nella
schedulazione dei thread il controllo viene passato a questo thread,
non attende qualche millisecondo e poi basta ma si pianta fintantochč
premo il tasto. Premendolo perň non posso piů accettare nuovi client.
Avendo un getchar non bloccante, se il controllo passa al thread del
main che fa questo lavoro e nessun tasto viene premuto (si vuole
ancora il server attivo), il thread viene rimesso di nuovo in attesa.

 
Ma blocca per 5 secondi ;-)
Ciao
Giovanni


            tv.tv_usec = 0;
Ok, invece di usare il membro tv_sec, puoi usare quello
sotto (tv.tv_usec) che indica i millisecondi; quindi
abbassando a circa 100/150 millisecondi, ottieni come effetto
collaterale il comportamento di kbhit() e quindi quello che
cercavi tu...

 Basic...
Stai molto attento: quando si dice che non esiste una via conforme allo 
standard del linguaggio per raggiungere certi scopi, NON si sta 
affermando che non sia possibile raggiungere certi scopi.  Il C non è 
Visual Basic, cioè non è un sistema di sviluppo strettamente integrato a 
un sistema, ma un linguaggio che segue specifiche standard.  Quando si 
confronta il C al Visual Basic, bisogna considerare una piattaforma 
specifica e praticamente su ogni piattaforma specifica esiste almeno un 
modo per assolvere allo stesso scopo della INKEY$ del Visual Basic. 
Ogni implementatore, su ogni piattaforma, è libero di "arricchire" il 
compilatore del linguaggio delle estensioni necessarie a programmare su 
quella piattaforma.  Lo standard del linguaggio impone certe regole per 
quel che riguarda il "core" del linguaggio, ma un programma che abbia 
senso su certe piattaforme deve necessariamente sfruttare gli standard 
di sviluppo di quelle piattaforme (vedi l'uso delle API Win32 sotto 
Windows o POSIX nei sistemi Unix-like o vattelapesca).  Tanto per fare 
un esempio, il DJGPP (porting DOS del gcc), così come il Borland C++ 5.5 
hanno un header non standard chiamato "conio.h" in cui sono riportati i 
prototipi di funzioni come la getch().  In Visual C++ esistono altri 
header e così via.

header e cosě via.
si, ho capito, intendevo dire che non esisteva uno standard in c per
fare questo.
La soluzione di Giovanni puň essere trasportata anche ad un sistema
windows?
Perchč altrimenti sono costretto a fare un uso pesante di #ifdef e
compagnia bella per far compilare parti di codice sia in linux e sia
in windows, del tipo:
#ifdef LINUX
parte di codice LINUX
...
#else ifdef WINDOWS
parte di codice WINDOWS


scrisse:

Si, in un certo senso, il tempo di attesa può essere considerato
trascurabile.
Ma questa soluzione ha una buona portabilità, rispetto all'altra
proposta?
Il tutto poi è complicato dal fatto che dovrei fare un programma
multithreading dove colui che aspetta è il thread main che fa questo:
.
.
.
while(1)
{
	acceptNONBLOCCANTE();
	if c'è un nuovo client crea un nuovo thread;
}	if getcharNONBLOCCANTEocodiceequivalente() == TASTOESCI break;
.
.
.
quindi, 1 decimo di secondo può degradare molto le prestazioni se il
thread main viene eseguito molte volte?

 windows?
Normalmente no.  Però ci sono compilatori come il Dev C++, ad esempio, 
che consentono una facile migrazione da un sistema all'altro, di 
software scritto seguendo lo standard POSIX.  Normalmente, comunque, un 
programma che sfrutta pesantemente le API di un particolare sistema non 
è facilmente trasportabile su un altro.

software scritto seguendo lo standard POSIX.  Normalmente, comunque, un 
se dovessi utilizzare le pthread su linux potrei senza problemi
trasportare lo stesso codice su windows?

 
Dovrebbe essere possibile perchè dovrebbe esiste un porting
delle pthread su win...
ma è anche possibile "traslare" le stesse funzioni pthread
con quelle API di win che eseguono lo stesso compito!

 
Non credo proprio: è abbastanza trascurabile come effetto collaterale


scrisse:

per "traslare" cosa intendi?
ci sono però delle differenze nella gestione dei thread nei due
sistemi.

Non credo proprio: è abbastanza trascurabile come effetto collaterale
bene, se utilizzo select su linux e WaitForSingleObject su win dovrei
aver risolto i miei problemi... forse.
Grazie

 sistemi.
Su win usi le API e su Linux le librerie pthread
Nessuna differenza...già usate in entrambi con lo stesso intento

 trasportare lo stesso codice su windows?
Esiste il porting delle pthread sotto Windows, ma purtroppo non è perfetto.

 Nessuna differenza...già usate in entrambi con lo stesso intento
L'intento di Gioacchino, da quello che ho capito, è quello di ottenere 
la portabilità del codice.  Se deve usare due API distinte, allora siamo 
d'accapo a 12.

 d'accapo a 12.
Ok...allora beccati questo gioacchino:
http://sourceware.org/pthreads-win32/
Ciao 

Gioacchino wrote:

Non è perfetto nel senso che è pieno di bug o mancano dei pezzi?
Il programma che dovrò fare fa parte di un progetto e si chiede la
portabilità sia in windows che in linux.


scrisse:

Ho dato un'occhiata e mi sembra portabile!
Faccio qualche prova e poi ti farò sapere.
Grazie dell'aiuto.
Ciao!

 Ho dato un'occhiata e mi sembra portabile!
Lo č.

 Non č perfetto nel senso che č pieno di bug o mancano dei pezzi?
No, vanno bene, ma lavorano meglio sotto Linux.  Provale.

No, vanno bene, ma lavorano meglio sotto Linux.  Provale.
Ora mi metto al lavoro...