시그널 핸들러에서 free () 또는 close ()를 실행할 수 있습니까? [복제]

Dec 10 2020

다음과 같은 코드가 있습니다.

//global variables

void signal_handler() {
    //deallocation of global variables
    free(foo);
    close(foo_2);
    exit(0);
}

int main () {
    signal(SIGINT, signal_handler);

    //irrelevant code
}

보시다시피 프로세스를 즉시 종료하는 대신 한 번 함수 CTRL+C를 실행하도록 인터럽트를 변경 signal_handler했습니다. 나는 어딘가에서 일부 기능 free이 비동기 안전하지 않고 실행되지 않을 수 있다는 것을 읽었 signal_handler지만 확실하지 않습니다.

내가 좋아하는 기능을 실행할 수 있습니다 free, close, exit또는 pthread_join에서 신호 처리기를?

답변

1 dratenik Dec 10 2020 at 15:46

아니요. man 7 신호 안전에 나열된 함수 만 신호 처리기 내부에서 호출해도 안전합니다.

close나열되며 안전해야합니다. free아니다. 소스 코드 (잠금 포함)를 확인해야하는 이유 때문입니다. exit임의의 정리 처리기를 호출 할 수 있기 때문에 안전하지 않습니다. 당신은 _exit정리없이 갑자기 종료됩니다.

1 MarcoBonelli Dec 10 2020 at 15:46

기술적으로 시그널 핸들러에서 이러한 함수를 호출하는 프로그램을 컴파일 할 수 있습니다. 그러나 실행하려는 함수가 비동기 신호 안전이 아닌 경우 정의되지 않은 동작이 발생합니다. 안전하지 않은 함수가 당신이 말한 것처럼 "실행되지 않는"것과는 다릅니다.하지만 그것은 여전히 ​​정의되지 않은 동작입니다.

비동기 신호 안전 함수 목록은 man 7 signal-safety. close()하면서 기능은 안전 free()하고 phtread_join()하지 않습니다. 또한이 exit()함수는 신호 처리기에서 호출하는 것이 안전 하지 않습니다. 이러한 컨텍스트에서 종료하려면 _exit()대신 사용해야 합니다.

신호를 수신 할 때 비동기 신호에 안전하지 않은 함수를 안전하게 호출하는 유일한 방법은 호출 (예 : 전역 변수 설정)을 "기억"한 다음 신호 처리기에서 돌아온 후에 수행하는 것 입니다.

1 JohnBode Dec 10 2020 at 16:30

짧은 대답은 아니오입니다.

7.1.4 라이브러리 함수 사용
...
4 표준 라이브러리의 함수는 재진입이 보장되지 않으며 정적 또는 스레드 저장 기간으로 객체를 수정할 수 있습니다. 188)
188) 따라서 시그널 핸들러는 일반적으로 표준 라이브러리 함수를 호출 할 수 없습니다.
C 2011 온라인 초안

결과의 실제 예-저는 Access 데이터베이스와 통신하는 시스템에서 작업했습니다. 를 사용하여 콘솔에 오류 메시지를 쓰려고 시도한 신호 처리기가 fprintf있었지만 신호 처리 프로세스 중에 어떻게 든 stderr데이터베이스를 저장 한 .mdb 파일에 매핑되어 헤더를 덮어 쓰고 데이터베이스를 복구 할 수 없게 망쳤습니다.

솔직히 다른 곳에서 확인할 플래그를 설정하는 것 외에 시그널 핸들러에서 할 수있는 일은 많지 않습니다 .

BasileStarynkevitch Dec 10 2020 at 16:24

시그널 핸들러에서 free () 또는 close ()를 실행할 수 있습니까?

당신은 절대로 안됩니다. 참조 신호 (7) 및 신호 - 안전 (7)

실제로는 절반 이상이 원하는 것처럼 작동 할 수 있습니다. IIRC, GCC 컴파일러는 원하는대로 작동하며 일반적으로 작동합니다.

더 나은 접근 방식은 ( 신호 처리기 내부에서 ) pipe (7)에 write (2) 를 사용하고 때때로 poll (2) 또는 관련 항목 을 사용하여 파이프 (주 프로그램에서)를 확인하는 것입니다.

또는 시그널 핸들러에서 일부 volatile sigatomic_t flag;(아마도)를 설정하고 _Atomic다른 곳 (메인 프로그램, 시그널 핸들러 외부)에서 해당 플래그를 확인할 수 있습니다.

Qt는 제가 몇 분 안에 할 수있는 것보다 더 잘 설명하고 있습니다.

Linux에서는 signalfd (2) 및 eventfd (2) 도 참조하십시오 .