I am trying to use the c++ standard input stream cin to get a user input without blocking the execution of the program. I have this code:
char ch;
int flag=1;
do
{
if(cin.rdbuf()->in_avail())
{
cin.get(ch);
flag=0;
}
else
//do something else
}while(flag);
//do something with the input
The idea here is to wait for user input without blocking while doing something else and as soon as the user provides an input we process the input( all in one thread). I know from the documentation the streambuf class used by the input stream provides the in_avail() function which will return a non-zero values when ever there is input ready in the buffer. The code above is not working as i expected it and is looping forever even if i provide a keyboard input at some point. i am using MS visual studio 2005 in windows 7. what am i missing here?
The function in_avail does:
Returns the number of characters available in the get area.
The get area may be empty even if some characters are readable from the underlying operating system buffer.
You will trigger a refill of the get area when you effectively call a read operation on the streambuf. And that operation will block. The reason is that the method underflow which is responsible for filling the get area:
Ensures that at least one character is available in the input area
And to ensure this, it must block until some character is read.
Related
I have a program I'm trying to write that constantly monitors a log file and outputs specific items into a new file.
I'm using essentially.
for (int i = 1; i < y; i ++)
getline(read, line); // skips to the last known end
while (getline(read, line))
{
cout << line;
}
read.clear();
I also keep track of the line I'm on just using the increment operator on a variable. At the end of the file I clear the eof bit and seek to the last line I was on. From using the debugger it seems that it works. I retrieve the next line in the file as its being written but when I call back to my while (getline(read,line)); it skips going through the while loop, why is that?
program reads the last line in the file.
Sleeps for 5 minutes.
The input file has had new lines added to it from a third party.
After the sleep it wakes up and goes back to the while loop.
It successfully retrieves the new lines from the input. But fails to
enter the while loop again
When using std::getline() at the end of a file both std::iostate::eofbit and std::iostate::failbit are set. In fact, it is std::iostate::failbit which causes the loop to exit. You'll need to clear both of these flags prior to any seek.
For a system which needs to use IOStreams I would actually not bother reading the leading lines but merely wait a bit, clear the flags, and try again. The main issue is detecting whether a complete line is read which could be done by simply reading individual characters, e.g., using std::istreambuf_iterator<char>.
Otherwise I'd look for a system API which provide some sort of indication that new data is available on a file. Older system generally don't provide such facilities but newer system generally have some event-based interface which can be used to get hold of newly available data. The advantage is normally that the processes doesn't poll for new data but idly waits until it gets notified about new data. I haven't used it myself but it seems libuv does this sort of operations in a somewhat platform-independent form.
Here is my code for test:
#include<iostream>
using namespace std;
istream& func(istream &);
int main()
{
if(func(cin))
cout<<"good"<<endl;
return 0;
}
istream& func(istream &is)
{
int num;
is.clear();
auto old_state = is.rdstate();
while(is>>num)
cout<<num<<endl;
is.setstate(old_state);
return is;
}
The problem is:if I enter a char or the mark of EOF(ctr_z in my system) to break the while loop,then the program terminates directly.I was expecting that the cin stream can be reset to a normal state and be returned:
if(func(cin))
cout<<"good"<<endl;
But I can't get that output when program ends.
So what's wrong with my understanding?
You need to ignore the eror and then clear it. So as an example you just need to change your while loop to something like this:
while(true)
{
if(is>>num)
cout<<num<<endl; //if cin is numeric
else // we have an error
{
is.ignore(); // ignore the last error (else your program will run crazy)
is.clear(); // clear the state
break; // terminate console reading
}
}
It's because setstate does not really clear the old flags (read the linked reference to see why)
If you want to completely reset the flags then you need to use the clear function. Not that I really recommend it though, as it gives you a false state of the stream. Instead you should explicitly check the state.
The state can be recovered after an invalid input: failure to parse the input according to the expected type just sets std:: ios_base::failbit which can be clear()ed. Since the character causing the problem is not removed, you'll probably need to get rid of it (e.g. using ignore()) or parae the data differently.
Although EOF is also just a flag (std::ios_base::eofbit) clearing it in general won't recover the from having reached the end of the stream. Specific streams may have a way to carry on reading but the console is likely to be disconnected after an end of stream indicator (e.g., Ctrl-D or Ctrl-Z). Depending on the system it may be possible to create a new connection to the console, e.g., by opening a file stream to /dev/tty.
If you really want to use control characters to indicate special processing you'll need to disable the default processing and manage them within the program. On UNIX systems you'd set the stream into noncanonical mode using tcgetattr() and tcsetattr(). Once this is done all characters entered are seen and can be processed accoringly, probably in a custom stream buffer. I don't know how to do something similar on other systems.
I know that this may be a stupid question but I am not sure how getting user input from the terminal actually works.
I understand input/output conceptually and I have no problem using them but I am lost when it comes to how these are actually implemented at a basic level.
As far as I know all stream objects use a type of buffer. If you extract all the characters you reach eof. It's this part I am probably wrong and I would like to know more about. For instance when we use the std::cin's extractor operator, it waits for input. How does it differentiate between waiting for input and reaching eof (nothing else to read) ?
std::cin doesn't do anything special. Like all file input, it
emits a system level read (read in Unix, ReadFile in
Windows), for enough bytes to fill its buffer (usually something
well over 1K today). It is the system which detects that the
input is from a keyboard, and behaves differently: from a file,
the system will read as many bytes as are available, up to the
end of file or the number requested, and return immediately.
From the keyboard, the system will normally read the characters
into an internal buffer until enter, to allow editing (back
space, etc.), and only on enter will it pass this buffer back to
the caller (after having appended the new line marker).
EDIT:
Sort of as a summary as to elements mentionned in the
discussion: I'll take as an example what happens in a Unix
system (but Windows is basically the same, modulo the way it
reports the different information). The istream itself is
buffered. When you try to extract a character (an >>
operator, istream::get, etc.), the stream will return it from
its buffer. If there are no more characters left in the buffer,
it will make a read request to the system, with the address
and the size of its buffer. (On todays systems, I would be
surprised to see a buffer of less than 1K.) What the system
does with it will depend on what the file descriptor designates:
a file
The system will copy bytes from the current position in the
file, until it has filled the buffer or reached end of file. It
returns the number of bytes it copies (or -1, if there is an
error).
a keyboard
For keyboards, the system maintains an internal buffer of
its own, and reads line by line. This buffer will only be
considered "ready" when the user presses enter; before that, the
system will simply not return from the `read`. This allows the
system to implement line editing; e.g. processing things like
a backspace. When you hit enter, the system adds the (system
specific) new line sequence to the buffer, and returns with the
number of characters it has copied into the buffer. (Thus, not
0, since there is the new line.) This procedure can be modified
in two ways: both Unix and Windows have a special characters
(control-D under Unix, control-Z under Windows) which tells the
system to return immediately from the read, with whatever the
buffer contains at the moment. If you're at the start of
a line, the buffer contains nothing, the `read` returns
0 characters read, and the stream treats it as an end of file.
And if the stream buffer size is less than the number of characters in
the line (because you've calmly typed in 100000 characters
without a new line), `read` will return the maximum that will
fit in the buffer, and the next `read` will return immediately
with the rest of the line (or the next n `read` will return
immediately, until the entire line has been read).
a pipe
The system will wait until either there are as many
characters as requested in the pipe, or there are no more
processes left with the pipe open for write. It will then copy
the number of characters requested (or less, of the write side
is closed), and return the number copied.
If the read indicates an error, the stream will set badbit;
if the read returns 0 characters read, the stream will treat
it as end of file.
A std::istream might have a limited amount of data (a file on a hard drive, ...) or an unlimited amount of data (a sensor, ..., interactive user input). In addition there might be a special character representing EOF.
An interactive input from a console/terminal is an infinite input. Unless a special character is entered (Linux: ctl-d), the stream never reaches EOF.
A non interactive input from a pipe will (should/might) end in a EOF.
I feel like there are a lot of similar questions, so I'm really sorry if this is a duplicate. I couldn't find the answer to this specific question, though.
I am confused as to how getline works when cin is passed to it, because my understanding is that it should be calling cin each time it is called. When working with code that was in a book I'm reading though, getline is called several times yet only one input is sent. The cin object is not called from anywhere except for within these getline calls.
What's going on here? When getline is reached does the program simply stop in its tracks and wait for the input stream to pass a value including the desired delimiter? If this is the case, do the subsequent getline calls just not have to wait because the input stream already has data including their respective delimiters? I ran a couple tests that would suggest this could be the case.
Here is the code:
string firstName;
getline(cin,firstName,',');
string lastName;
getline(cin,lastName,',');
string job;
getline(cin,job,'\n');
cout<<firstName<<" "<<lastName<<" is a "<<job<<endl;;
Sorry again if this is a stupid question, but I looked around and genuinely could not find the answer. Thanks in advance for any help that can be provided!
Clarification:
This code outputs "First Last is a Job" for the console input "First,Last,Job\n"
A call to a function using cin is not actually a request for user input (at least not directly). It is a request for characters from the standard input. In normal program operation (where standard input is not being directed from a file or other source) standard input is stored in a buffer. If the standard input buffer is empty, and cin is requesting more characters, then your system will request input from the user via the terminal. (i.e. the keyboard). This input which the terminal requests is generally line oriented. That is, it waits for you to press the Enter key, then sends all the data to be stored in the standard input buffer. If cin gets all the characters it needs before the input buffer is empty, those characters remain until the next request.
So, for example, when you make this call:
getline(cin,firstName,',');
and the input buffer is empty, Let's say the user inputs this:
Benjamin, Lindley, Software DeveloperEnter
First, the following string is stored in the input buffer:
"Benjamin, Lindley, Software Developer\n"
Then getline causes "Benjamin," to be read from the input buffer (but discards the comma).
" Lindley, Software Developer\n"
remains in the buffer for any future operations with cin.
getline does not "call" cin at all. cin is an object. Objects contain data. The data in cin is the information needed by input functions to read the standard input stream. If you wanted to read from a file, for instance, you'd open the file and pass the file object to getline instead.
When getline is called, the program reads whatever is in the input buffer. If the input buffer already contains the delimiter then getline will return right away. Otherwise it will wait.
I one part of my application I have used Sleep(5000) (I need to wait 5 sec)
The problem is that if the user presses any keyboard key during these 5 seconds, the keys will be read after sleep and it causes problems for my app.
How can I empty the buffer after sleep?
I tried cin.clear() and setbuf(stdin, NULL) but they can't clear the buffer if there is more than one character in the buffer.
The two functions you are using don't have the effect you expect them to have:
clear() doesn't affect the buffer at all but rather clears the error flags. That is, if there was an unsuccessful read a flag is set (std::ios_base::failbit). While any error flag is set (there are a few more), the stream won't attempt to read anything.
setbuf(0, 0) affects the stream's internal buffer to not exist (calls with non-null values have implementation-defined meaning which is typically "do nothing"). This is generally a Bad Idea because it causes the streams to be very slow. Also, the keys pressed by a user are probably not stored in this buffer anyway but rather in the operating systems input buffer until they are sent to application (there are platform specific ways to turn off the operating system input buffer, e.g., on POSIX you'd use tcsetattr() to set the input into non-canonical mode).
In either case, not having a buffer doesn't really help you anyway: The user may very well have typed valid input. The proper approach is to attempt reading the available input and, if this fails, to rid of the offending character (or characters). To this end you'd attempt to read the input and if it fails you'd clear() the stream and ignore() one or more characters (this example ignores an entire line; call ignore() without parameters to just ignore one character):
T value;
while (!(std::cin >> value)) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
You always need to verify that the input was successful anyway and the few extra lines are just adding a bit of recovery code.
The simplest way to clear the keyboard input buffer is
while(kbhit()) getch();
just put that code in your program wherever you want to clear your buffer .
headerfile needed for that is conio.h
This seems to work for Windows 10 compiled with Code::Blocks:
#include <conio.h>
/**
* clears keyboard buffer
*
* #author Shaun B
* #version 0.0.2
* #fixed 15-01-2016
*/
void clearKeyboardBuffer()
{
while (_kbhit())
{
_getche();
}
}
Then called from where is needed in your C++ script.