Re: Using std::cin.rdbuf()->in_avail()
Paul wrote:
I have a small command-line (console) application which, I thought, it would
be good to allow users to pause and to resume - or exit. To control this,
users will enter input at the command prompt. Actual processing occurs in a
different thread.
Here is a fragment of the code accepting user input:
---------------------------------------------------
std::cout << "Enter choice: 'P' - pause, 'Q' - quit: ";
char ch;
while (!finish) {
if (std::cin.rdbuf()->in_avail()) {
Note that in_avail is useful for getting characters that the OS has
transferred to cin, but which you haven't yet read. In effect, it tells
you have many characters you are *guaranteed* to be able to read without
cin blocking. However, it may be the case (and usually is in fact) that
in_avail will report fewer characters than can be read without blocking.
In particular, it will often report 0 even when there is some input waiting.
if (std::cin >> ch) {
You realise the above skips whitespace?
std::cin.sync(); // flush remaining characters
cin.sync() doesn't do anything. Instead, you should ignore the number of
characters you want to flush. E.g. to flush remaining known buffered chars:
std::cin.ignore(std::cin.rdbuf()->in_avail());
or to flush until the next newline character:
std::cin.ignore(
std::numeric_limits<std::streamsize>::max(),
static_cast<unsigned char>('\n')
);
To flush all other console input (e.g. unknown buffered chars) you can do:
FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
Is there a way to cause, say, some termination
code in the thread doing processing to unblock std::cin when it is no longer
needed or is there perhaps a better way to use .in_avail()?
Usually, under these circumstances, you would wait for signals on two
object, std::cin's Windows file handle (get it with
GetStdHandle(STD_INPUT_HANDLE)) and an event object FINISHED. e.g.
HANDLE hFinished = CreateEvent(NULL, FALSE, FALSE, NULL);
//...
HANDLE hStdInput = GetStdHandle(STD_INPUT_HANDLE);
HANDLE const hArray[2] = {hFinished, hStdInput};
bool finished = false;
while (!finished)
{
DWORD ret = WaitForMultipleObjects(2, hArray, FALSE, INFINITE);
switch (ret)
{
case WAIT_OBJECT_0:
finished = true;
return; //finished
case WAIT_OBJECT_0 + 1:
{
char c;
if (std::cin.get(c))
{
//deal with c
}
//flush everything else?
std::cin.ignore(std::cin.rdbuf()->in_avail());
FlushConsoleInputBuffer(hStdInput);
}
break;
default:
//error handling
}
}
The code to exit should call:
SetEvent(hFinished);
Tom