Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible to stop cin from waiting input?

In a graphical application I execute debug commands using the console input. When the console is created a new thread is also created to gather the user commands that handles all that input, the graphical application continues running parallel. I use boost::thread library.

It works good so far, however I haven't found a nice solution to stop the execution of this thread. The thread is always waiting for a user input:

 while(appRunning)
 {
     std::cin>>theUserCommand;
     // ...do stuff
 }

Then when the graphical application ends, it will stop all console functions, in which I include the thread:

 appRunning = false;
 // do some more related clean up
 myListeningThread->join();

As you can see the std::cin will be waiting for user input, after the join has being called. One of the solutions I tried is to create events "synthetizing keystrokes", the std::cin will get whatever value you send with an ENTER, the thread will end nicely, this solutions is horrible and I don't want to keep it. Besides, it did work in one of the environments the tool is executed, but fails when I tried using it along with a UI API. Could you guys guide me how can I fix this in a correct way? Can't really say for sure if in the C++ documentation there is a function to stop std::cin waiting for user input, and just and continue the program execution, is it even possible?

EDIT: Fine I find that keybd_event is a bit misleading for some environments, explicitly specifying the input handler with the WriteConsoleInput works good.

like image 553
notNullGothik Avatar asked Dec 19 '11 23:12

notNullGothik


1 Answers

I am not much of a Windows programmer, I know a whole lot more about Unix. And I am totally unfamiliar with boost::thread. That said, based on the advice at the bottom of this MSDN page, here is my recommendation:

  • Create an event object before you create the console-reading thread.
  • When you want to shut down, call SetEvent on the event object immediately before calling the thread's ->join method.
  • Change the main loop in your console-reading thread to block in WaitForMultipleObjects rather than istream::operator>>, something like this:

    for (;;) {
        HANDLE h[2];
        h[0] = GetStdHandle(STD_INPUT_HANDLE);
        h[1] = that_event_object_I_mentioned;
        DWORD which = WaitForMultipleObjects(2, h, FALSE, INFINITE);
    
        if (which == WAIT_OBJECT_0)
            processConsoleCommand();
        else if (which == WAIT_OBJECT_0 + 1)
            break;
        else
            abort();
    }
    
  • This thread must take care not to do any blocking operation other than the WaitForMultipleObjects call. Per the discussion in the comments below, that means processConsoleCommand can't use cin at all. You will need to use the low-level console input functions instead, notably GetNumberOfConsoleInputEvents and ReadConsoleInput, to ensure that you do not block; you will need to accumulate characters across many calls to processConsoleCommand until you read a carriage return; and you will also need to do your own echoing.

like image 121
zwol Avatar answered Sep 25 '22 11:09

zwol