Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Program with loop will not terminate with CTRL + C

Tags:

c

infinite

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?

like image 922
humra Avatar asked Aug 26 '14 09:08

humra


People also ask

How do I stop a program from running in C?

So the C family has three ways to end the program: exit(), return, and final closing brace.

Is Ctrl C a SIGINT?

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.

How do I terminate a program using Ctrl D?

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.


Video Answer


3 Answers

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.

like image 83
webuster Avatar answered Oct 17 '22 01:10

webuster


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.

like image 37
Paul R Avatar answered Oct 17 '22 00:10

Paul R


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

like image 2
rookie coder Avatar answered Oct 17 '22 00:10

rookie coder