2010-11-22 2 views

답변

24

기본적으로 대부분의 신호로 인해 프로그램이 즉각적이고 비정상적으로 종료됩니다.

그러나 대부분의 신호에 대한 기본 동작을 쉽게 변경할 수 있습니다. 이 프로그램을 누르 제어-C를 실행하면

#include <iostream> 
#include <signal.h> 
#include <unistd.h> 
#include <cstring> 
#include <atomic> 

std::atomic<bool> quit(false); // signal flag 

void got_signal(int) 
{ 
    quit.store(true); 
} 

class Foo 
{ 
public: 
    ~Foo() { std::cout << "destructor\n"; } 
}; 

int main(void) 
{ 
    struct sigaction sa; 
    memset(&sa, 0, sizeof(sa)); 
    sa.sa_handler = got_signal; 
    sigfillset(&sa.sa_mask); 
    sigaction(SIGINT,&sa,NULL); 

    Foo foo; // needs destruction before exit 
    while (true) 
    { 
     // do real work here... 
     sleep(1); 
     if(quit.load()) break; // exit normally after SIGINT 
    } 
    return 0; 
} 

, 당신은 단어 "소멸자"을 참조해야합니다

이 코드는 모든 일반적인 소멸자를 호출을 포함하여, 일반적으로 신호 종료 프로그램을 만드는 방법을 보여줍니다 인쇄. 시그널 핸들러 함수 (got_signal)는 실제로 무엇을하고 있는지 알지 못하는 한, 플래그를 설정하고 조용하게 돌아 오는 것 이외의 다른 일을해서는 안된다는 것을 알아 두십시오.

대부분의 신호는 위의 그림과 같이 catch 가능하지만 SIGKILL은 제어 할 수 없습니다. SIGKILL은 사용자가 프로세스를 정지시킬 수있는 SIGSTOP이 아니라 runaway 프로세스를 종료하는 마지막 수단입니다. 원하는 경우 SIGTSTP (control-Z)를 잡을 수는 있지만 신호에 대한 관심 만이 소멸자 동작 인 경우에는 필요하지 않습니다. 결국 컨트롤 -Z에서 프로세스가 깨어나고 계속 실행되며 모든 소멸자가 효과를 발휘하여 정상적으로 종료됩니다.

+5

IIRC의 올바른 유형의'quit'은'volatile std :: sig_atomic_t'이어야합니다. 이런 목적으로'bool'을 사용하는 것은 UB입니다. – MSalters

+0

@MSalters : 맞습니다. sigaction() 전에 sigfillset() 호출을 포함시켜야합니다. 아마도 sig_atomic_t보다 훨씬 좋을 것입니다. bool을 사용하면 추가 신호가 신호 처리기 인터럽트를 차단할 때보다 익숙하고 완벽하게 안전합니다. 내 예제 코드를 수정했습니다. –

+2

사실이 코드는'quit = false' 라인에'delete function 사용'오류가 있습니다. 'quit = false' 대신'quit (false)'를해야합니다. 또한이 코드가 Windows에서 작동하지 않는다는 점에 유의할 가치가 있습니다. 당신은'SetConsoleCtrlHandler()'를 사용해야합니다. – Timmmm

8

이러한 신호를 직접 처리하지 않으면 아니오, 소멸자가 호출되지 않습니다. 그러나 운영 체제는 프로그램이 종료 될 때 사용한 모든 자원을 회수합니다.

신호를 직접 처리하려면 sigaction 표준 라이브러리 기능을 확인해보십시오.

+3

OS 소유의 자원 재생. 응용 프로그램에는 다른 자원이 있으며 일반적으로 올바르게 닫히는 방법으로 포장됩니다 (그렇지 않으면 제대로 종료되지 않은 파일과 같은 손상된 자원이 생깁니다). –

6

의 그것을 시도하자 다음

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

class Foo { 
public: 
    Foo() {}; 
    ~Foo() { printf("Yay!\n"); } 
} bar; 

int main(int argc, char **argv) { 
    sleep(5); 
} 

과 :

$ g++ -o test ./test.cc 
$ ./test 
^C 
$ ./test 
Yay! 

그래서 난 두렵지 않아, 당신이 그것을 잡을해야합니다.

SIGSTOP은 캐치 될 수 없으며 SIGCONT이 전송 될 때까지 프로세스를 일시 중지합니다.

관련 문제