2

All my research has lead to there is no standard way to do this, but someone must have this lying around in some way or another.

Long story short, I need an (effective, i know it doesn't exist) std::readline with timeout. I'd prefer a cross platform way, but I'm actually writing for windows so I'll take that if nessisary. I allready have a boost dependency, so I don't mind using boost.

My forays down the path of boost::asio always seem to end in dead ends: for example:

How to asynchronously read input from command line using boost asio in Windows?

The conclusion seems to be that you just can't use the stdin handle with that solution.

Anyone got a better way?

Community
  • 1
  • 1
IdeaHat
  • 7,641
  • 1
  • 22
  • 53
  • 1
    Ryan Dahl has written a substantial piece on this [topic](http://tinyclouds.org/iocp-links.html). – Kevin A. Naudé Sep 26 '13 at 20:04
  • Yeah, so you will need to extract the OS "HANDLE" value from the stream. For stdio you would use fileno() and _get_osfhandle(). Then, from a 2nd thread you could call CancelIoEx(). The trick is coordinating with that 2nd thread to make the timeout work. Each time you read you would have to tell the 2nd thread to restart the timeout. – joeking Sep 26 '13 at 20:08
  • @joeking I'm not sure that knowing the handle will actually be enough to make it work. Unless I am mistaken, the object that lies beneath STDIN on Windows is an anonymous pipe, and those don't support any form of non-blocking IO. I am interested in this -- can you confirm that your suggestion works? – Kevin A. Naudé Sep 26 '13 at 20:13
  • @joeking Oh, I see what you are suggesting. However, if you need to use another thread to call CancelIoEx, isn't it better to just do the IO in another thread anyway? – Kevin A. Naudé Sep 26 '13 at 20:18
  • I cannot confirm - I've not tried it myself - but CancelIoEx. Oh I forgot something that is better.... Get the HANDLE, then call WaitForSingleObject(h, timeout). When Wait returns success you can read from the handle without blocking. Now, fstream adds layers of buffering so you will need to disable the buffering to get the read operation to directly read from the OS handle. – joeking Sep 26 '13 at 20:19
  • It doesn't look like fstream allows you to get the FILE* it uses, but you can create a stream given an FILE*. I think it would probably be better to write a "kevenReadLine()" function that calls WaitForSingleObject() and ReadFile() directly instead of relying on really specific behavior in fstream. – joeking Sep 26 '13 at 20:21
  • @joeking Dumb question, I can just use that to interrupt any io in windows? That may be good enough for me, being that I just want to get out of the block to check for the thread termination condition. – IdeaHat Sep 26 '13 at 20:21
  • Presumably, yes. However, it is tricky - you must be really careful to *not* call CancelIoEx(h, null), where "h" is a handle which has already been closed. This is true for any Windows function which takes a file HANDLE -- never ever attempt to use a HANDLE that has been closed because that handle value can get reused immediately for the next file that is opened in any thread in the process. – joeking Sep 26 '13 at 20:23
  • For additional reference, I am linking to this [related SO question](http://stackoverflow.com/questions/11294954/non-blocking-read-of-stdin). – Kevin A. Naudé Sep 26 '13 at 20:31
  • @joeking Also, it looks like using the event stream, I'd have to handle all key presses (including arrow keys and return). Is this seriously so rarely done that there isn't a boilerplate for this? – IdeaHat Sep 26 '13 at 21:26
  • Maybe use SetConsoleMode to disable things like ENABLE_WINDOW_INPUT ? Yes, this does suck. OK, try this: Create another thread which only reads from the console, stuffs the data into a buffer and sets a signal. Now, your main thread can wait on that signal and read data from the buffer until it is empty. The program will exit when the main thread exits and the main thread doesn't have to deal with the console input directly at all, while the extra thread doesn't need to bother with timeouts. – joeking Sep 26 '13 at 21:53
  • @joeking So you are suggesting just leaving the read thread hanging after main quits? that won't cause any issues? – IdeaHat Sep 26 '13 at 22:29
  • @MadScienceDreams Yes. "main()" isn't really the first line of code executed. The CRT has a bunch of startup/teardown code which does a bunch of stuff like global variable construction and atexit handling. When main() returns, the CRT startup code will terminate the process. The worst thing that could happen is if you have other threads active and using some global variables (with destructors) which get torn down by the CRT - could result in occasional crashes on exit. Alternatively you could call _exit() to skip global variable destruction and just die. – joeking Oct 12 '13 at 00:34

0 Answers0