2011-12-19 11 views
8

In un'applicazione grafica eseguo i comandi di debug utilizzando l'ingresso della console. Quando viene creata la console, viene creato anche un nuovo thread per raccogliere i comandi utente che gestiscono tutto quell'input, l'applicazione grafica continua ad essere parallela. Io uso la libreria boost :: thread.È possibile interrompere l'attesa da parte di cin?

Funziona bene finora, tuttavia non ho trovato una buona soluzione per interrompere l'esecuzione di questo thread. Il filo è sempre in attesa di un input da parte dell'utente:

while(appRunning) 
{ 
    std::cin>>theUserCommand; 
    // ...do stuff 
} 

Poi, quando si conclude l'applicazione grafica, che verrà interrompere tutte le funzioni della console, in cui includo il filo:

appRunning = false; 
// do some more related clean up 
myListeningThread->join(); 

Come si può vedere la std :: cin aspetterà l'input dell'utente dopo che è stato chiamato il join. Una delle soluzioni che ho provato è creare eventi "sintetizzando sequenze di tasti", lo std :: cin otterrà qualunque valore tu invii con un INVIO, il thread terminerà bene, questa soluzione è orribile e non voglio mantenerla . Inoltre, ha funzionato in uno degli ambienti in cui è stato eseguito lo strumento, ma non riesce quando ho provato ad usarlo insieme a un'API dell'interfaccia utente. Potresti aiutarmi ragazzi come posso risolvere questo in modo corretto? Non posso davvero dire con certezza se nella documentazione del C++ c'è una funzione per fermare std :: cin in attesa di input dell'utente, e solo e continuare l'esecuzione del programma, è possibile?

EDIT: Bene, trovo che keybd_event sia un po 'fuorviante per alcuni ambienti, specificando esplicitamente il gestore di input con WriteConsoleInput che funziona correttamente.

+0

Ci sono diverse possibilità, ma tutte sono dipendenti dal SO. Per quale sistema operativo è questo programma? – zwol

+0

Win/VStudio9.0, ho usato il keybd_event per la soluzione che ho menzionato, non ci sono problemi se sarà dipendente dal sistema operativo. come mi consiglieresti di aggiustarlo? – notNullGothik

+0

BTW, SetConsoleCtrlHandler non funziona davvero per me, questo finirà il processo dell'applicazione ignorando tutte le operazioni di pulizia per far terminare l'applicazione. – notNullGothik

risposta

1

Non sono un programmatore di Windows, so molto di più su Unix. E non ho assolutamente familiarità con boost::thread. Detto questo, sulla base del parere in fondo this MSDN page, qui è la mia raccomandazione:

  • Creare un event object prima di creare il thread di console-lettura.
  • Quando si desidera arrestare, chiamare SetEvent sull'oggetto evento immediatamente prima di chiamare il metodo ->join del thread.
  • Modificare il ciclo principale nel tuo thread console-lettura per bloccare in WaitForMultipleObjects piuttosto che istream::operator>>, qualcosa di simile:

    for (;;) { 
        HANDLE h[2]; 
        h[0] = GetStdHandle(STD_INPUT_HANDLE); 
        h[1] = that_event_object_I_mentioned; 
        DWORD which = WaitForMultipleObjects(2, h, FALSE, INFINITE); 
    
        if (which == WAIT_OBJECT_0) 
         processConsoleCommand(); 
        else if (which == WAIT_OBJECT_0 + 1) 
         break; 
        else 
         abort(); 
    } 
    
  • Questo thread deve fare attenzione a non fare alcuna operazione di blocco diversa dalla chiamata WaitForMultipleObjects . Per la discussione nei commenti qui sotto, che significa processConsoleCommand non è possibile utilizzare cin affatto. Dovrai utilizzare lo low-level console input functions invece, in particolare GetNumberOfConsoleInputEvents e ReadConsoleInput, per assicurarti di non bloccare; sarà necessario accumulare caratteri attraverso molte chiamate a processConsoleCommand finché non si legge un ritorno a capo; e dovrai anche fare il tuo eco.

+0

Si noti che il blocco sullo standard input usando 'WaitForMultipleObjects()' per evitare una lettura bloccante è fondamentalmente inaffidabile. Se l'input standard è la tastiera (dispositivo CONIN $ '), quindi premendo un tasto qualsiasi (anche quelli, come' CTRL', che non producono input) sbloccherà l'attesa solo per bloccare la successiva operazione di input indefinitamente, dando come risultato la discussione che ignora lo stato dell'evento. Dai un'occhiata a [domanda correlata] (http://stackoverflow.com/questions/8347642/checking-win32-file-streams-for-available-input) per maggiori dettagli. –

+0

Non importa se questo thread termina la rotazione con 'WaitForMultipleObjects' quando l'utente sta digitando, a patto che vada in idle quando l'utente * non sta * digitando. Mi piacerebbe pensare che ci sia un equivalente di ['FIONREAD'] (http://www.daemon-systems.org/man/ioctl.2.html) che può essere usato per assicurare che' ReadFile' non blocchi, ma Windows mi ha sorpreso con l'assenza di strutture simili prima. Se qualcosa del genere non può essere fatto funzionare, penso che starei cercando di implementare la mia finestra della console con le API della GUI. – zwol

+0

... La discussione in quella domanda correlata in realtà non aiuta; la raccomandazione sembra essere "usa un thread dedicato per leggere dalla console" e qui stiamo discutendo su come implementare precisamente tale thread. – zwol

Problemi correlati