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
.



Relevant Pages

  • Re: Y&R - Melody Tomas Scott / Nikki goes to war with TPTB
    ... WAY, WAY bad for morale, especially for those who have been there for ... decades and gone over and beyond during times when the show was flush. ... characters go, spend less on sets, wardrobe, ... expensive clothing, or even letting some of the non-essential ...
    (rec.arts.tv.soaps.cbs)
  • Re: OS X USB/RS232 problems (somewhat OT)
    ...  Loop the adapter back on itself (i.e. connect pin 2 to pin ...  Then send it a bunch of characters ... Ron, it seems that like me, you thought that the flush should block ... until everything in the buffer has been sent. ...
    (comp.lang.lisp)