1

I'm working on a Console class for console IO (right now just input, though) and I'm polling input from std::cin in my loop by having a background thread constantly checking for input. However, while it reads input fine, I (expectedly) ran into an issue where after I close my main window (GLFW) the console window is still sitting in the background waiting to either be closed out or receive input. I'm looking for a way to terminate the thread, but couldn't find any information on a good way to do it for this scenario. Any ideas?

console.h

class Console
{
    public:
        Console();
        ~Console();

        bool isInputAvailable();
        std::string pullLastInput();

    private:
        bool do_quit;
        void thread_input();
        std::thread in_thread;
        std::queue<std::string> input_queue;
};

console.cpp:

Console::Console() : in_thread(&Console::thread_input, this)
{
    do_quit = false;
}

Console::~Console()
{
    do_quit = true;
    in_thread.join();
}

bool Console::isInputAvailable()
{
    return input_queue.size() > 0;
}

std::string Console::pullLastInput()
{
    std::string input;
    input = input_queue.front();
    input_queue.pop();

    return input;
}

void Console::thread_input()
{
    std::string input;
    while (!do_quit)
    {
        std::cin >> input;

        input_queue.push(input);
    }
}
Jake Johnson
  • 33
  • 1
  • 4
  • This post might be helpful: http://stackoverflow.com/questions/18868114/telling-an-stdthread-to-kill-stop-itself-when-a-condition-is-met – jithinpt May 01 '15 at 18:54
  • As the above post illustrates, you need to update the do_quit variable within a mutex or declare its type as std::atomic. Else, the update made by one thread may not be seen by the other. – jithinpt May 01 '15 at 18:57
  • 2
    That doesn't solve the problem at all. The `thead_input` is blocked on `std::cint >> input` line indefinitely, the `atomic` ness of `do_quit` is irrelevant. – Yakk - Adam Nevraumont May 01 '15 at 18:58
  • @jithinpt While this is probably formally true, I am quite sure that the blocking call inside `std::cin::operator>>` will act as a synchronization point on any reasonable platform. – sbabbi May 01 '15 at 18:59
  • 1
    I don't believe you can do this. You could consider reading from the console via lower-level operations. – Yakk - Adam Nevraumont May 01 '15 at 19:01
  • 2
    Do you have posix? (A: probably). If so, `select` and manually reading from `stdin` with an abort signal would solve your problem. With some work, we could even make it the back-end to a stream. – Yakk - Adam Nevraumont May 01 '15 at 19:58
  • Be interesting to see what closing standard in would do, but @Yakk's got the right of it. Cin isn't built for that sort of use. – user4581301 May 01 '15 at 19:59

2 Answers2

1

In your main window, when quitting, either by using the onClose event or in the destructor function, call std::terminate or the destructor of the background thread.

Terminating threads is explained here: How do I terminate a thread in C++11?

And close event handling in GLFW: http://www.glfw.org/docs/latest/group__window.html#gaade9264e79fae52bdb78e2df11ee8d6a

Community
  • 1
  • 1
pjsofts
  • 170
  • 4
  • 18
1

There is no way to do that portably.

A quick solution on posix involves pthread_cancel. This will abruptly terminate the thread, leaking any resource currently held by the terminating thread.

For this reason is usually considered a bad practice, but in your case you are going to terminate the program anyway, so it might work for you. Consider redesigning your program by using lower-level I/O so that you can do a timed-out wait on the user input.

The relevant changes to your code, after including pthread.h, are:

Console::~Console()
{
     pthread_cancel( in_thread.native_handle() );
     in_thread.join();
}

//Get rid of the quit variable
void Console::thread_input()
{
     std::string input;
     while (true)
     {
        std::cin >> input;
        //Btw, you need a mutex here.
        input_queue.push(input);
     }
 }
sbabbi
  • 11,070
  • 2
  • 29
  • 57