5

My program has many different threads handling different things, and one of them deals with user input.

The other threads don't have much in the way of blocking calls, and those that do block are network based so will be interrupted or return gracefully when the socket is shut down.

However the user thread has calls to std::cin in order to grab the user input. The effect this has is while all the other threads are dead the user thread is still blocking on user input, and will only die the next time input is given.

Is there any way for me to check if there is any user input to grab before blocking?

I understand cin.peek() exists but from my experience, it blocks if there is nothing to read in. Assuming I'm using it correctly

My code is basically an infinite loop that stops when another thread switches the condition variable:

void doLoop()
{
    while (running) //running is shared between all threads and all others die quickly when it is false. It's set to true before the threads are started
    {
        string input = "";
        getline(cin, input);

        //Handle Input

    }
}

I'm on windows, using VS2013, and cannot use external libraries. I'm using windows.h and std throughout.

22
  • 1
    Depends on your actual OS, but you might be interested in check out for select() or poll() to overcome these problems. Commented Dec 30, 2014 at 18:37
  • Should have mentioned that, I'm on windows
    – Force Gaia
    Commented Dec 30, 2014 at 18:38
  • Can you just explicitly kill the user input thread when the program stops running?
    – Nathan S.
    Commented Dec 30, 2014 at 18:39
  • Kill it how? I'm creating the thread as a std::thread, and didn't think there was a way to kill them remotely. I'd rather not pursue this, but will main thread termination kill remaining threads safely?
    – Force Gaia
    Commented Dec 30, 2014 at 18:42
  • @ForceGaia That was clear to me, but since all that stuff actually is OS dependent, you should have tagged so maybe. The std::thread options might still give you some feasible solution. Commented Dec 30, 2014 at 18:44

2 Answers 2

1

I believe that the C++ Standard does not offer a way of checking the standard input without blocking. Since you are willing to use platform specific functions, 'kbhit()' might suit your needs but it has been deprecated in Windows. An alternative is offered, _kbhit(). Of course this is not portable to other platforms.

This is the link to MSDN: _kbhit

4
  • that link mentions "This API cannot be used in applications that execute in the Windows Runtime" what exactly does that mean? is that only if i were to pack it as a DLL?
    – Force Gaia
    Commented Dec 30, 2014 at 19:25
  • @ForceGaia It means you cannot use it in Windows Store apps.
    – imreal
    Commented Dec 30, 2014 at 19:27
  • checking kbhit() before doing the getline would still result in the same problem if the user has begun typing but did not enter yet, or changed his mind and aborts entering text. Commented Dec 30, 2014 at 22:31
  • @ForceGaia you'll have to use get() instead of getline()
    – imreal
    Commented Dec 31, 2014 at 18:14
0

What you could do is using futures to allow the user to input something with a time limit. You can then insert this code into your main loop

#include <iostream>       // std::cout
#include <future>         // std::async, std::future
#include <chrono>         // std::chrono::milliseconds
#include <string>
using namespace std;


bool myAsyncGetline(string & result)
{
    std::cout<<"Enter something within the time limit"<<endl;
    getline(cin,result);
    return true;
}

int main()
{
  // call function asynchronously:
  string res;
  std::future<bool> fut = std::async (myAsyncGetline,res); 


  std::chrono::seconds span (20);
  if (fut.wait_for(span)==std::future_status::timeout)
    std::cout << "Too Late!";
  else
      cout<<"You entered "<<res<<" "<< endl;

  return 0;
}

This is available in VS2012 so you should be able to reproduce it.

The output is "Tool Late!" if getline is still working after the timeout (20s), otherwise it outputs the result.

I think that it is simpler than messing around with killing thread as the function stop by itself if the time limit is hit. Tell me if you need help integrating it into your existing code I can assist.

4
  • Looks like a place to start, but I don't think it'll work. the way i see it every time myAsyncGetline is called the timer immediately starts. so if the user starts typing on the 19th second of that timer, a second later it times out and they lose their input. However it has given me an idea, as it means that i can keep checking if a string is empty (as it'll only have something in it when the user hits enter), restart teh async if the string isn't empty, and i can plonk the timeout after the loop so i can kill the async when the thread is supposed to die. I'll have a mess about with this.
    – Force Gaia
    Commented Dec 30, 2014 at 21:09
  • ok keep me updated I am curious about that bcz I think future can simplify code.
    – Gabriel
    Commented Dec 30, 2014 at 21:11
  • yes, and that's what makes me question this method. will fut.wait_for(span) actually kill the thread?
    – Force Gaia
    Commented Dec 31, 2014 at 15:14
  • It will kill it if the timeout is reached. here for more details. cplusplus.com/reference/future/async and codeproject.com/Articles/857201/Cplusplus-Concurrency-New
    – Gabriel
    Commented Dec 31, 2014 at 15:44

Not the answer you're looking for? Browse other questions tagged or ask your own question.