windowsmultithreadingc++11stdinmsvc12

Exit application while stdin blocking on windows


I have an application, which reads data from standard input using getline() in a thread. I want to close the application from the main thread, while getline still block the other thread. How can this be achieved?

I don't want to force the users to have to press ctrl-Z to close stdin and the application.

I have tried so far with my complier settings (RuntimeLibrary=/MT) on Windows 8.1 64bit, v120 platform toolset:

* Update *

* Update 2: Solution *


Example code showing the problem:

#include <iostream>
#include <thread>
#include <string>
#include <chrono>

int main(int argc, char *argv[])
{
    bool stop = false;
    std::thread *t = new std::thread([&]{
        std::string line;
        while (!stop && std::getline(std::cin, line, '\n')) {
            std::cout << line;
        }
    });

    std::this_thread::sleep_for(std::chrono::seconds(1));

    stop = true;
    // how to stop thread or make getline to return here?

    return 0;
}

Solution

  • writeConsoleInput() can make std::getline return from blocking read, so it can solve the problem even when /MT compiler option used.

    #include <Windows.h>
    
    #include <iostream>
    #include <thread>
    #include <string>
    #include <chrono>
    #include <atomic>
    
    int main(int argc, char *argv[])
    {
        std::atomic_bool stop;
    
        stop = false;
    
        std::thread t([&]{
            std::string line;
            while (!stop.load() && std::getline(std::cin, line, '\n')) {
                std::cout << line;
            }
        });
    
    
        std::this_thread::sleep_for(std::chrono::seconds(1));
    
        stop = true;
    
        DWORD dwTmp;
        INPUT_RECORD ir[2];
        ir[0].EventType = KEY_EVENT;
        ir[0].Event.KeyEvent.bKeyDown = TRUE;
        ir[0].Event.KeyEvent.dwControlKeyState = 0;
        ir[0].Event.KeyEvent.uChar.UnicodeChar = VK_RETURN;
        ir[0].Event.KeyEvent.wRepeatCount = 1;
        ir[0].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
        ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC);
        ir[1] = ir[0];
        ir[1].Event.KeyEvent.bKeyDown = FALSE;
        WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), ir, 2, &dwTmp);
    
        t.join();
    
        return 0;
    }