Exit the application when stdin is blocked on windows

I have an application that reads data from standard input using getline () in a stream. I want to close the application from the main thread, while getline is still blocking another thread. How can this be achieved?

I do not want users to press ctrl-Z to close stdin and the application.

I already tried with the settings of my compiler (RuntimeLibrary = / MT) on Windows 8.1 64bit, v120 platform toolet:

  • freopen stdin, but it is locked by an internal lock
  • breaking the thread calling abort ()
  • putback a Eof, end of line in std :: cin, which also blocked

* Update *

  • detach () does not work, exit () is locked by a lock
  • winapi TerminatThread () causes interrupt ()
  • winapi CloseHandle (GetStdHandle (STD_INPUT_HANDLE)) freezes
  • calling TerminateProcess () - works, but I would like to exit gracefully

* Update 2: Solution *

  • WriteConsoleInput () can convert std :: getline () from a read lock. This works with any msvc runtime libray. For a working solution code, see Accepted Answer.

Sample 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; } 
+5
source share
6 answers

writeConsoleInput () can make std :: getline return from the read lock, so it can solve the problem even if the / MT compiler option is 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; } 
+2
source

Just disconnect the stream:

 #include <iostream> #include <thread> #include <chrono> bool stop = false; int main(int argc, char *argv[]) { std::thread t([]{ bool stop = false; 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; // Without detach: g++: terminate called without an active exception t.detach(); return 0; } 

Cleaner ways

  • If stdin receives user input, you have the correct output in the stream (do not interrupt interactive input, not in blue)
  • Non-blocking read from stdin (which is system dependent)
  • Pipeline setup
  • Using socket
0
source

There is no standard or even cross-platform solution for interrupting std:cin or std::thread . In both cases, you will need to use OS-specific APIs. You can get an OS specific handle for a thread with std::thread::native_handle()

As a quick and dirty hack, you can just detach thread. But keep in mind this and that .

 int main(int argc, char *argv[]) { std::thread t([&] { std::string line; while (std::getline(std::cin, line, '\n')) { std::cout << line; } }); t.detach(); std::this_thread::sleep_for(std::chrono::seconds(1)); } 

also:

  • No need to allocate a thread to the heap:

     std::thread t([]{ }); 
  • return 0; not required in C ++
  • stop = true; will cause a compilation error because stop not declared in this area
  • If you plan on sharing the boolean flag this way, you will have a typical race condition and thus UB
  • Probably the closest to a "standard" or "cross-platform" solution for non-blocking input might be ncurses (as it is on * nix and pdcurses on Windows)
0
source

If nothing works, there is always a nuclear option:

 TerminateProcess(GetCurrentProcess(), 0); 

Just make sure you flush all the buffers you need.

0
source

this code is multi-threaded. First of all, why create a new thread on the heap? just declare it on the stack and call std::thread::detach .
secondly, who promised you that stop in this context will work? it is more than possible that the processor caches this logical value and never looks at the real one (unless you partially optimize it or other compilation tricks ..). you need to make it 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; } }); t.detach(); stop = true; } 

compiled with visual studio 2013 on Windows 7 and works as expected.

0
source

This works for me, although it's a bit quirky:

 #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; CloseHandle(GetStdHandle(STD_INPUT_HANDLE)); t.join(); return 0; } 
0
source

All Articles