Exiting an infinite loop with a key in c++ on linux - c++

i have an infinite loop that should be ended if i pressed any key. The program runs in linux. I have stumbled upon a function Here is a bit of my code :
int main(){
While(1){
ParseData(); //writing data to a text file
}
return 0;
}
so i know that i can terminate the process by using ctrl + c in terminal, but it seems that it will interrupt the writing process so the datas are not written completely halfway through the process. I read that i need to use function from ncurses library , but i can't quite understand any.
Can someone help me with it? Thanks!

You can declare an atomic_bool and move your main loop to another thread. Now you can wait with a simple cin, once the user presses any key you exit your loop.
std::atomic_boolean stop = false;
void loop() {
while(!stop)
{
ParseData(); // your loop body here
}
}
int main() {
std::thread t(loop); // Separate thread for loop.
// Wait for input character (this will suspend the main thread, but the loop
// thread will keep running).
std::cin.get();
// Set the atomic boolean to true. The loop thread will exit from
// loop and terminate.
stop = true;
t.join();
return 0;
}

Why do you need a key to exit a program that didn't finish writing to a file, even if you make the loop exits on key press it will interrupt the file writing too if not finished.
Why you just exit the loop when the data finishes writing to the file, like the following:
isFinished = false;
While(!isFinished ){
ParseData(); //writing data to a text file
//after data finsihes
isFinished = false;
}

thread.cpp
#include <atomic>
#include <iostream>
#include <thread>
std::atomic<bool> dataReady(false);
void waitingForWork(){
std::cout << "Waiting... " << std::endl;
while ( !dataReady.load() ){
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
std::cout << "Work done " << std::endl;
}
int main(){
std::cout << std::endl;
std::thread t1(waitingForWork);
std::cout << "Press Enter to Exit" << std::endl;
std::cin.get();
dataReady= true;
t1.join();
std::cout << "\n\n";
}
g++ -o thread thread.cpp -std=c++11 -pthread

The C way actually (include conio.h ):
char key;
while (1)
{
key = _getch();
// P to exit
if (key == 'p' || key == 'P')
{
writer.close();
exit(1);
}
}

Related

Destroy/replace thread on timer or command outside from the main thread

Currently I'm working on server development for an online game and decided to implement it as multithreaded application.
I have a main thread which implements while loop which abstractly gets data from the socket.
std::vector<std::thread> games_threads;
int start(int game_id) {
std::this_thread::sleep_for(std::chrono::seconds(10));
return end(game_id);
}
int end(int game_id) {
// some other conditions for turn end
return start(game_id);
}
int main() {
// socket implmementation
while(1) {
Message msg = socket.get_data();
switch(msg->action) {
case GAME_START:
std::thread game_thread(start, create_game());
game_thread.detach();
games_threads.push_back(game_thread);
break;
case TURN_END:
std::thread game_thread(end, msg->get_game());
game_thread.detach();
games_threads.push_back(game_thread);
break;
}
}
}
Game creates with turn start() method. And then after waiting 10 secs in call end() method which implements turn end.
After than turn end() method calls start().
But I need also implement force turn end method so I have race condition with 2 cases:
Start -> End normal workflow with 10s timeout (which makes game
thread unavailable for 10 secs)
Forced turn end command (TURN_END).
So I need somehow end the current game thread and replace with one user thread. Or just catch signals somehow with conditional variable but I have already freeze for 10sec and as far as I know I can't wait both things at the same time (conditional variable and sleep ending).
Maybe multithreading is not a good solution at all. Please share your approach in this case.
Thanks
Its not so much that multi-threading is a bad approach as your specific implementation is not right.
A call to the start() function or end() function will never return because they each call each other in a never ending recursion. This is already bad since your stack will be filling up as you enter deeper into function calls.
But that aside, your main loop starts a new thread when you call GAME_START and this new thread goes into its "forever" start()<-->end() loop. "OK" so far, but then when the TURN_END is called your main loop calls end() directly and therefore your main loop also now enters a forever start()<-->end() loop. This now means both your main and your "worker" thread are locked up in these loops that don't return - so no more messages can be processed from your socket.
I would suggest that your main loop uses a condition variable to signal your worker loop to force a new turn.
I am not quite sure what to suggest to replace your start()<-->end() recursion loop because its not clear to me what this is trying to achieve. But possibly a timer class might work here (the example is the first one I found in google)
Complete Example Using Stdin
Here the start function implements a thread loop instead of calling end/start repeatedly... Also the game ID 1 gets ended when you enter end the other games continue as normal. All games exit when you enter exit
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <algorithm>
#include <atomic>
#include <chrono>
#include <condition_variable>
std::vector<std::thread> games_threads;
std::condition_variable cv;
std::mutex cv_m;
int the_game_id = 0;
int start(int id) {
int game_id = id;
bool running = true;
while (running)
{
std::unique_lock<std::mutex> lk(cv_m);
auto now = std::chrono::system_clock::now();
std::cout << "THREAD " << game_id << ": Waiting for turn..." << std::endl;
// Wait for the signal to end turn only if the game ID is for us.
if(cv.wait_until(lk, now + std::chrono::seconds(10), [&game_id](){return (the_game_id == game_id || the_game_id == -1);}))
{
// Condition var signalled
if (the_game_id == -1)
{
std::cout << "THREAD" << game_id << ": end game - exit" << std::endl;
running = false;
}
else
{
std::cout << "THREAD" << game_id << ": turn end forced" << std::endl;
// Reset the game ID so we don't keep triggering
the_game_id = 0;
}
}
else
{
// 10 second timeout occured
std::cout << "THREAD" << game_id << ": 10 seconds is up, end turn" << std::endl;
}
}
std::cout << "THREAD" << game_id << ": ended" << std::endl;
return 1;
}
int main() {
// pretend socket implmementation - using stdin
int id = 1;
bool done = false;
while(!done) {
std::string cmd;
std::getline(std::cin, cmd);
if (cmd == "start")
{
std::cout << "starting..." << std::endl;
games_threads.push_back({ std::thread( [&id](){ return start(id++); } ) });
}
else if (cmd == "end")
{
std::cout << "ending..." << std::endl;
// Notify game ID 1 to end turn - (but in reality get the ID from the message)
the_game_id = 1;
cv.notify_all();
}
else if (cmd == "exit")
{
std::cout << "exiting all threads..." << std::endl;
// Notify game ID 1 to end turn
the_game_id = -1;
cv.notify_all();
done = true;
}
}
// Tidyup threads
for (auto &th : games_threads)
{
if (th.joinable())
{
th.join();
}
}
}
Output:
> start
starting...
THREAD 1: Waiting for turn...
> start
starting...
THREAD 2: Waiting for turn...
> start
starting...
THREAD 3: Waiting for turn...
> end
ending...
THREAD1: turn end forced
THREAD 1: Waiting for turn...
THREAD2: 10 seconds is up, end turn
THREAD 2: Waiting for turn...
THREAD3: 10 seconds is up, end turn
THREAD 3: Waiting for turn...
THREAD1: 10 seconds is up, end turn
THREAD 1: Waiting for turn...
> exit
exiting all threads...
THREAD1: end game - exit
THREAD1: ended
THREAD2: end game - exit
THREAD2: ended
THREAD3: end game - exit
THREAD3: ended

C++: GetAsyncKeyState() does not register key press immediately

In the program I am writing when I hit the 'escape' key, I want it to register immediately, even during the sleep period. Currently it waits until the end of the sleep statement before registering the key press. The sleep time is important to the program, so it is not a matter of just adding a pause and waiting on user input.
int main()
{
bool ESCAPE = false; // program ends when true
while (!ESCAPE) {
// Stop program when Escape is pressed
if (GetAsyncKeyState(VK_ESCAPE)) {
cout << "Exit triggered" << endl;
ESCAPE = true;
break;
}
Sleep(10000);
}
system("PAUSE");
return 0;
}
EDIT: To clarify, the reason for the sleep is that I am performing an action repeatedly on a time interval.
Instead of sleeping for 10 seconds, you can check if 10 seconds is passed, and do whatever needs to be done at that point. This way the loop is checking constantly for a keypress.
#include <chrono>
...
auto time_between_work_periods = std::chrono::seconds(10);
auto next_work_period = std::chrono::steady_clock::now() + time_between_work_periods;
while (!ESCAPE) {
// Stop program when Escape is pressed
if (GetAsyncKeyState(VK_ESCAPE)) {
std::cout << "Exit triggered" << std::endl;
ESCAPE = true;
break;
}
if (std::chrono::steady_clock::now() > next_work_period) {
// do some work
next_work_period += time_between_work_periods;
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}

C++ Delay For-Loop without pausing Console

I am trying to create a function that will be done many times over and over but with a pause in between each cycle.
I have tried to use "sleep" but that pauses the console. And I have searched online and only found answers that paused the console during usual.
Code:
int i;
for(i=0; i<500; i++) {
std::cout << "Hello" << std::endl;
}
How can I make it print "Hello" 500 times and as well allow the user to use the console while it is doing the said function?
As some people commented, you need to create an async task in order to do some work while still handling user input.
The following is a minimal, working example about how to acomplish this task by using a thread. It is based on boost so you'll have to link it using -lboost_thread lboost_system:
g++ test.cpp -lboost_thread -lboost_system -o test
The code has several comments in order to explain what you should do:
#include <queue>
#include <iostream>
#include <boost/thread.hpp>
// set by the main thread when the user enters 'quit'
bool stop = false;
boost::mutex stopMutex; // protect the flag!
// the function that runs in a new thread
void thread_function() {
// the following is based on the snippet you wrote
int i;
for(i=0; i<500; i++) {
// test if I have to stop on each loop
{
boost::mutex::scoped_lock lock(stopMutex);
if (stop) {
break;
}
}
// your task
std::cout << "Hello" << std::endl;
// sleep a little
::usleep(1000000);
}
}
int main() {
std::string str;
boost::thread t(thread_function);
while(true) {
std::cout << "Type 'quit' to exit: ";
// will read user input
std::getline(std::cin, str);
if (str == "quit") {
// the user wants to quit the program, set the flag
boost::mutex::scoped_lock lock(stopMutex);
stop = true;
break;
}
}
// wait for the async task to finish
t.join();
return 0;
}

Multi-threaded event checker does not print anything

Code:
#include <iostream>
#include <future>
#include <queue>
#include <boost/thread/thread.hpp>
boost::mutex mtx;
std::queue<std::string>ev;
void t_1(){
while(true){
mtx.lock();
if(ev.size() > 0){
std::cout << ev.front();
ev.pop();
}
mtx.unlock();
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
}
}
void t_2(){
int x = 0;
while(true){
x++;
mtx.lock();
ev.push("new event");
mtx.unlock();
boost::this_thread::sleep_for(boost::chrono::milliseconds(1000));
}
}
void t_3(){
while(true){
std::cout << 3;
}
}
int main(int argc, const char * argv[]) {
// insert code here...
boost::thread t1(t_1);
boost::thread t2(t_2);
//boost::thread t3(t_3);
t1.join();
t2.join();
while(true){
std::cout << "anyone there";
}
//t3.join();
return 0;
}
I was messing around with the boost library, and wanted to make an event checker using threads and mutexes. For some reason there is no output, even on the main thread when it should print "anyone there." I am using Mac OSX and Xcode. THe program compiles and runs just fine.
As already mentioned by #krzaq your main loop does not print anything because join waits for the termination of the thread, which will never happen due to the endless loops in t_1 and t_2.
As for your t_1 output: You have no newline in your output. Typically the output buffer is flushed only on a newline, which means that you will not see the output flushed to your terminal until you either print a newline or the buffer is filled up.
Try this:
std::cout << ev.front() << "\n";
Your threads never finish, and you join() them (that is, wait for them to finish) before the printing loop in the main thread.
t1.join(); // the main thread never gets past this point

"Safely" terminate a running C++ program on keypress?

I'm trying to write a simulation that will carry on running until I press a certain key (like 'q' for quit). Then after I press that, I want the program to finish writing the data its currently writing, close files, then gracefully exit (as opposed to just pressing ctrl+c to force the program to stop). Is there any way to do this on C++?
Thanks
Have the user press CTRL-C, but install a signal handler to deal with it. In the signal handler, set a global boolean variable, for example user_wants_to_quit. Then your sim loop can look like:
while ( work_to_be_done && !user_wants_to_quit) {
…
}
// Loop exited, clean up my data
A complete POSIX program (sorry, if you were hoping for Microsoft Windows), including setting and restoring the SIGINT (CTRL-C) handler:
#include <iostream>
#include <signal.h>
namespace {
sig_atomic_t user_wants_to_quit = 0;
void signal_handler(int) {
user_wants_to_quit = 1;
}
}
int main () {
// Install signal handler
struct sigaction act;
struct sigaction oldact;
act.sa_handler = signal_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, &oldact);
// Run the sim loop
int sim_loop_counter = 3;
while( (sim_loop_counter--) && !user_wants_to_quit) {
std::cout << "Running sim step " << sim_loop_counter << std::endl;
// Sim logic goes here. I'll substitute a sleep() for the actual
// sim logic
sleep(1);
std::cout << "Step #" << sim_loop_counter << " is now complete." << std::endl;
}
// Restore old signal handler [optional]
sigaction(SIGINT, &oldact, 0);
if( user_wants_to_quit ) {
std::cout << "SIM aborted\n";
} else {
std::cout << "SIM complete\n";
}
}