I have a program that I want to run until interrupted by user pressing CTRL + C. When I press it nothing happens and I can only terminate the program by suspending it and manually killing it after that.
This is the part of the code that needs to run infinitely:
while(true) {
liveOrDie(field);
printOut(field);
}
The first function calculates whether to put 1 or 0 in a two dimensional array and the second one prints it out using a for loop like this:
void printOut(int field[38][102]) {
for(int i = 0; i < 38; i++) {
for(int j = 0; j < 102; j++) {
if(field[i][j] == 1) {
cout << "o";
}
else {
cout << " ";
}
}
cout << endl;
}
system("sleep .1");
}
Sleep is used so there is enough time to print everything out on the screen before it is cleared.
So, program doesn't terminate by Ctrl+C
. What may cause this behavior, and how to make the program terminate after Ctrl+C
?
So the C family has three ways to end the program: exit(), return, and final closing brace.
SIGINT is the signal sent when we press Ctrl+C. The default action is to terminate the process. However, some programs override this action and handle it differently. One common example is the bash interpreter.
Ctrl + D will cause the stdin file descriptor to return end-of-file. Any input-reading function will reflect this, and you can then exit the program when you reach end-of-file.
From the documentation of system()
(emphasis/bold mine):
The
system()
library function uses fork(2) to create a child process that executes the shell command specified in command using execl(3) as follows:execl("/bin/sh", "sh", "-c", command, (char *) 0);
system()
returns after the command has been completed.During execution of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored, in the process that calls
system()
(these signals will be handled according to their defaults inside the child process that executes command).
Which explains your behavior.
I suspect that the user code runs for some small amount of time, say 1 ms, and the sleep process causes the parent process to block for 100 ms, so unless you're very persistent with the CTRL + C key then the interrupt will most likely be ignored.
You should just replace your call to system("sleep .1")
with a proper library call, e.g. change:
system("sleep .1");
to:
usleep(100000); // NB: requires #include <unistd.h>
See: man usleep.
Have you tried catching the signal? See the example code below:
if (signal (SIGINT, yourFunctionHandler) == SIG_ERR)
{
cout << "Error setting the SIGINT handler";
}
void yourFunctionHandler (int signal)
{
cout << "Signal " << signal << " received!";
//do what's needed to kill loop
}
In this way you can modify the loop variable as you wish. And as other people suggested, don't use system().
Signal reference
Small tutorial
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With