Asynchronous console input

Started by
15 comments, last by loufoque 14 years, 10 months ago
I personally would just use platform dependent code. Create a function that wraps in_avail() and if it returns 0 then calls the appropriate function.
Advertisement
Quote:Original post by SiCrane
I personally would just use platform dependent code. Create a function that wraps in_avail() and if it returns 0 then calls the appropriate function.
Guess I will have to learn how to put Window's command prompt into non-blocking mode - plus it turns out the BSD and Linux termios structures are incompatible [wink]

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

You can't, not really. The console doesn't participate in true async operations like other files/streams, so you have to jury rig something yourself. One option would be to WaitForSingleObject on the console input, with a timeout period and poll the thread's exit condition if the timeout expires. When there is data available, you'll have to peek at the console's input queue to check whether it contains keyboard input, because mouse movements and window activity will also satisfy the wait in default mode.

This might come in handy. The check for keyboard input starts on line 112 and, in your case, hConIn would be the result of GetStdHandle(STD_INPUT_HANDLE). It is pure Win32 but there's nothing stopping you using std::cin once you know there's input available.
Quote:Original post by adeyblue
You can't, not really. The console doesn't participate in true async operations like other files/streams, so you have to jury rig something yourself...

This might come in handy.
Yuk!

The more I search, the more I think that the threading solution is the simplest/best. It is only a few lines of code, works on any platform with thread support, and the input thread will spend its entire lifetime blocked on std::getline(), so it won't consume a noticeable number of CPU cycles.

It looks like this:
#include <boost/thread.hpp>#include "LocklessQueue.h"#include <iostream>#include <string>LocklessQueue< std::string > commands(16);struct InputServer{	void operator () () {		while (1) {			std::string command;						std::getline(std::cin, command);						while (!commands.push(command))				; // spin till the main thread consumes a queue entry		}	}};int main() {	InputServer input;	boost::thread inputThread(input);		std::cout << "server launched.\n>> " << std::flush;		while (1) {		std::string command;				if (commands.pop(command)) {						if (command == "status")				std::cout << "server running...\n>> " << std::flush;			else if (command == "quit") {				std::cout << "bye!" << std::endl;				break;			} else {				std::cout << "unrecognised command.\n>> " << std::flush;			}		}	}		exit(0);}

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

I don't see why threading is such a bad idea. To me it seems like the perfect place to use it. You need to do two things at once: output text, and gather input. Threads allow you to do two things at once (more or less). Therefore, use threads. Can't argue with that logic [grin].

It may be a bit messy that you have to forcibly kill the blocking thread but if it works it works. Maybe you could quit when the user types "quit" or something, and exit the input thread neatly when that happens. Although the user could also quit by closing the console window.
[Window Detective] - Windows UI spy utility for programmers
Quote:Original post by XTAL256
It may be a bit messy that you have to forcibly kill the blocking thread but if it works it works.
Yeah, I am probably being overly pedantic. The input thread doesn't carry any heavy resources (just its own stack space), and the OS will cleanup everything as soon as the application exits, so forcibly killing it should be perfectly safe.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Just use the polling mechanisms of your OS.
On windows, WaitForSingleObject.
On linux/mac/unix, select.

This topic is closed to new replies.

Advertisement