views:

589

answers:

5

Hello, I am working in the Linux environment, and I have a C++ program, what I want is when I cancel the program with ctrl+c I would like that the program executes a function, to close some files and print some sutff, is there any way to do this?. Thank you.

A: 

Short answer: look into the signal function, specifically catching SIGINT. You write a callback function and pass it to the system via the signal function, then when that particular signal happens, the system calls your callback function. You can close files and do whatever other cleanup stuff you want in there.

Graeme Perrow
Much better to use sigaction().
Jonathan Leffler
+3  A: 

You have to catch the SIGINT. Something like this:

void sigint_handler(int sig)
{
    [do some cleanup]
    signal(SIGINT, SIG_DFL);
    kill(getpid(), SIGINT);
}

loads more detail here

Colin Pickard
Much better to use sigaction().
Jonathan Leffler
Jonathan - please expand on that assertion.
Alnitak
answer above expands on it (http://stackoverflow.com/questions/368927/call-a-function-when-the-program-is-finished-with-ctrl-c/376059#376059)
Colin Pickard
+3  A: 

For a full working example you can try the following code:

#include <signal.h>
#include <stdio.h>

volatile bool STOP = false;
void sigint_handler(int sig);

int main() {
    signal(SIGINT, sigint_handler);
    while(true) {
        if (STOP) {
            break;
        }
    }
    return 0;
}

void sigint_handler(int sig) {
    printf("\nCTRL-C detected\n");
    STOP = true;
}

Example run:

[user@host]$ ./a.out 
^C
CTRL-C detected
Jay
STOP should be declared volatile -- otherwise, the compiler might make some (incorrect) optimizations.
Adam Rosenfield
I'm no C++ expert so I'll take your word for it and update the code sample :-)
Jay
Technically, it should also be a sig_atomic_t too. POSIX allows you to do more in a signal handler than ISO C does. Also, you should use sigaction(). All else apart, if the user uses a program to generate two interrupts quickly, your program may die using signal() instead of sigaction().
Jonathan Leffler
A: 

Note to people who might stumble upon this question, looking for the answer in Windows instead:

Use the SetConsoleCtrlHandler API call to set a custom handler and watch for CTRL_C_EVENT, CTRL_BREAK_EVENT or CTRL_CLOSE_EVENT.

Ates Goral
+6  A: 

signal() can be dangerous on some OSes and is deprecated on Linux in favor of sigaction(). "signal versus sigaction"

Here's an example that I ran across recently ("Tap the interrupt signal") and modified as I was playing around with it.

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>

struct sigaction old_action;

void sigint_handler(int sig_no)
{
    printf("CTRL-C pressed\n");
    sigaction(SIGINT, &old_action, NULL);
    kill(0, SIGINT);
}

int main()
{

    struct sigaction action, old_action;
    memset(&action, 0, sizeof(action));
    action.sa_handler = &sigint_handler;
    sigaction(SIGINT, &action, &old_action);

    pause();

    return 0;
}
Mr. Muskrat
The actions in sigint_handler() after the printf() are odd - why? Also, you should pause() instead of your while loop. The initialization for the new action is not ideal, either. It probably works, but is a bit of scattershot "let's hope that all zeroes is OK" approach.
Jonathan Leffler
I have updated it to use pause() instead of the while loop as that really does make more sense even for demonstration code.As I said in the post, the code originally came from elsewhere. I may have misread it but I thought it would save off and restore any existing signal handlers.
Mr. Muskrat