시그널 핸들러에서 free () 또는 close ()를 실행할 수 있습니까? [복제]
다음과 같은 코드가 있습니다.
//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
에서 신호 처리기를?
답변
아니요. man 7 신호 안전에 나열된 함수 만 신호 처리기 내부에서 호출해도 안전합니다.
close
나열되며 안전해야합니다. free
아니다. 소스 코드 (잠금 포함)를 확인해야하는 이유 때문입니다. exit
임의의 정리 처리기를 호출 할 수 있기 때문에 안전하지 않습니다. 당신은 _exit
정리없이 갑자기 종료됩니다.
기술적으로 시그널 핸들러에서 이러한 함수를 호출하는 프로그램을 컴파일 할 수 있습니다. 그러나 실행하려는 함수가 비동기 신호 안전이 아닌 경우 정의되지 않은 동작이 발생합니다. 안전하지 않은 함수가 당신이 말한 것처럼 "실행되지 않는"것과는 다릅니다.하지만 그것은 여전히 정의되지 않은 동작입니다.
비동기 신호 안전 함수 목록은 man 7 signal-safety. close()
하면서 기능은 안전 free()
하고 phtread_join()
하지 않습니다. 또한이 exit()
함수는 신호 처리기에서 호출하는 것이 안전 하지 않습니다. 이러한 컨텍스트에서 종료하려면 _exit()대신 사용해야 합니다.
신호를 수신 할 때 비동기 신호에 안전하지 않은 함수를 안전하게 호출하는 유일한 방법은 호출 (예 : 전역 변수 설정)을 "기억"한 다음 신호 처리기에서 돌아온 후에 수행하는 것 입니다.
짧은 대답은 아니오입니다.
7.1.4 라이브러리 함수 사용C 2011 온라인 초안
...
4 표준 라이브러리의 함수는 재진입이 보장되지 않으며 정적 또는 스레드 저장 기간으로 객체를 수정할 수 있습니다. 188)
188) 따라서 시그널 핸들러는 일반적으로 표준 라이브러리 함수를 호출 할 수 없습니다.
결과의 실제 예-저는 Access 데이터베이스와 통신하는 시스템에서 작업했습니다. 를 사용하여 콘솔에 오류 메시지를 쓰려고 시도한 신호 처리기가 fprintf
있었지만 신호 처리 프로세스 중에 어떻게 든 stderr
데이터베이스를 저장 한 .mdb 파일에 매핑되어 헤더를 덮어 쓰고 데이터베이스를 복구 할 수 없게 망쳤습니다.
솔직히 다른 곳에서 확인할 플래그를 설정하는 것 외에 시그널 핸들러에서 할 수있는 일은 많지 않습니다 .
시그널 핸들러에서 free () 또는 close ()를 실행할 수 있습니까?
당신은 절대로 안됩니다. 참조 신호 (7) 및 신호 - 안전 (7)
실제로는 절반 이상이 원하는 것처럼 작동 할 수 있습니다. IIRC, GCC 컴파일러는 원하는대로 작동하며 일반적으로 작동합니다.
더 나은 접근 방식은 ( 신호 처리기 내부에서 ) pipe (7)에 write (2) 를 사용하고 때때로 poll (2) 또는 관련 항목 을 사용하여 파이프 (주 프로그램에서)를 확인하는 것입니다.
또는 시그널 핸들러에서 일부 volatile sigatomic_t flag;
(아마도)를 설정하고 _Atomic다른 곳 (메인 프로그램, 시그널 핸들러 외부)에서 해당 플래그를 확인할 수 있습니다.
Qt는 제가 몇 분 안에 할 수있는 것보다 더 잘 설명하고 있습니다.
Linux에서는 signalfd (2) 및 eventfd (2) 도 참조하십시오 .