2011-12-19 11 views
8

En una aplicación gráfica, ejecuto comandos de depuración usando la entrada de la consola. Cuando se crea la consola, también se crea un nuevo hilo para reunir los comandos del usuario que maneja toda esa entrada, la aplicación gráfica continúa ejecutándose en paralelo. Yo uso la biblioteca boost :: thread.¿Es posible detener cin de la entrada de espera?

Funciona bien hasta el momento, sin embargo, no he encontrado una buena solución para detener la ejecución de este hilo. El hilo está siempre a la espera de una entrada de usuario:

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

Luego, cuando termina la aplicación gráfica, se detendrá todas las funciones de la consola, en la que incluyo el hilo:

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

Como se puede ver la std :: cin esperará la entrada del usuario, después de que se haya llamado a la unión. Una de las soluciones que probé es crear eventos "sintetizando las pulsaciones de teclas", std :: cin obtendrá cualquier valor que envíe con un ENTRAR, el hilo terminará muy bien, esta solución es horrible y no quiero mantenerla . Además, funcionó en uno de los entornos donde se ejecuta la herramienta, pero falla cuando traté de usarlo junto con una API de UI. ¿Podrían guiarme cómo puedo solucionar esto de manera correcta? Realmente no puedo decir con certeza si en la documentación de C++ hay una función para detener std :: cin esperando la entrada del usuario, y solo y continuar la ejecución del programa, ¿es posible?

EDIT: bien Me parece que keybd_event es un poco engañoso para algunos entornos, especificando explícitamente que el manejador de entrada con WriteConsoleInput funciona bien.

+0

Existen varias posibilidades, pero todas dependen del sistema operativo. ¿Para qué sistema operativo es este programa? – zwol

+0

Win/VStudio9.0, utilicé keybd_event para la solución que mencioné, no hay problema si depende del sistema operativo. ¿Cómo me recomendarías que lo arreglara? – notNullGothik

+0

BTW, SetConsoleCtrlHandler realmente no funciona para mí, esto terminará el proceso de solicitud omitiendo toda la limpieza para que la aplicación finalice. – notNullGothik

Respuesta

1

No soy muy programador de Windows, sé mucho más sobre Unix. Y estoy totalmente familiarizado con boost::thread. Dicho esto, basándose en el asesoramiento en la parte inferior de this MSDN page, aquí está mi recomendación:

  • Crear event object antes de crear el hilo de la consola de lectura.
  • Cuando desee apagar, llame al SetEvent en el objeto de evento inmediatamente antes de llamar al método ->join de la secuencia.
  • Cambiar el bucle principal en su hilo de consola de lectura para bloquear en WaitForMultipleObjects en lugar de istream::operator>>, algo como esto:

    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(); 
    } 
    
  • Este hilo debe tener cuidado de no hacer ninguna operación de bloqueo que no sea la llamada WaitForMultipleObjects . Según la discusión en los comentarios a continuación, eso significa que processConsoleCommand no puede usar cin en absoluto. Necesitarás usar el low-level console input functions en su lugar, notablemente GetNumberOfConsoleInputEvents y ReadConsoleInput, para asegurarte de que no bloquees; deberá acumular caracteres en muchas llamadas al processConsoleCommand hasta que lea un retorno de carro; y también necesitarás hacer tu propio eco.

+0

Tenga en cuenta que bloquear en la entrada estándar usando 'WaitForMultipleObjects()' para evitar una lectura de bloqueo es fundamentalmente poco confiable. Si la entrada estándar es el teclado (dispositivo 'CONIN $'), al presionar cualquier tecla (incluso aquellas, como 'CTRL', que no producen entrada) se desbloqueará la espera solo para bloquear en la siguiente operación de entrada indefinidamente, lo que resulta en el hilo ignorando el estado del evento. Consulte una [pregunta relacionada] (http://stackoverflow.com/questions/8347642/checking-win32-file-streams-for-available-input) para obtener más detalles. –

+0

Realmente no importa si este hilo termina girando a través de 'WaitForMultipleObjects' cuando el usuario está escribiendo, siempre que permanezca correctamente inactivo cuando el usuario * no está * escribiendo. Me gustaría pensar que hay algún equivalente de ['FIONREAD'] (http://www.daemon-systems.org/man/ioctl.2.html) que se puede usar para asegurar que' ReadFile' no se bloquee, pero Windows me ha sorprendido con la ausencia de instalaciones similares antes. Si no se puede hacer que algo como esto funcione, creo que estaría buscando implementar mi propia ventana de consola con las API de GUI. – zwol

+0

... La discusión en esa pregunta relacionada realmente no ayuda; la recomendación parece ser "usar un hilo dedicado para leer desde la consola" y aquí estamos discutiendo cómo implementar precisamente dicho hilo. – zwol

Cuestiones relacionadas