수색…


통사론

  • void (* signal (int sig, void (* func) (int))) (int);

매개 변수

매개 변수 세부
시그 신호 처리기를 SIGABRT , SIGFPE , SIGILL , SIGTERM , SIGINT , SIGSEGV 또는 일부 구현 값 중 하나로 설정하는 신호
기능 시그널 핸들러는 다음 중 하나이다 : SIG_DFL , 디폴트 핸들러, SIG_IGN 을 무시하는 SIG_IGN , 서명이있는 함수 포인터 void foo(int sig); .

비고

C 표준의 보증만으로 신호 처리기를 사용하면 사용자 정의 신호 처리기에서 수행 할 수있는 작업과 수행 할 수없는 작업에 다양한 제한이 있습니다.

  • SIGSEGV , SIGFPE , SIGILL 또는 다른 구현 정의 하드웨어 인터럽트를 처리하는 동안 사용자 정의 함수가 반환되면 C 표준에 따라 동작이 정의되지 않습니다. 이것은 C의 인터페이스가 오류 상태 (예 : 0 으로 나누기)를 변경하고 프로그램을 반환 할 때 하드웨어 인터럽트가 발생하기 전과 완전히 동일한 오류 상태를 변경하기위한 수단을 제공하지 않기 때문입니다.

  • 사용자 정의 함수가 abort 또는 raise 호출의 결과로 호출 된 경우, 신호 핸들러는 raise 를 다시 호출 할 수 없습니다.

  • 신호는 모든 연산의 중간에 도착할 수 있으므로 일반적으로 연산의 불가분성을 보장 할 수 없으며 신호 처리가 최적화와 잘 작동합니다. 따라서 시그널 핸들러의 모든 데이터 수정은 변수

    • 형식 sig_atomic_t (모든 버전) 또는 잠금없는 원자 유형 (C11 이후, 선택 사항)
    • volatile 자격증입니다.
  • C 표준 라이브러리의 다른 함수는 일반적으로 프로그램의 전역 상태에서 변수를 변경할 수 있으므로 이러한 제한을 존중하지 않습니다. C 표준에 대해서만 보증하는 abort , _Exit (C99) 이후, quick_exit (C11) 이후, signal (동일 신호 번호), 및 어떤 작업 원 (C11) 이후.

위의 규칙 중 하나라도 위반하면 C 표준에 따라 동작이 정의되지 않습니다. 플랫폼에는 특정 확장명이있을 수 있지만 일반적으로 해당 플랫폼을 넘어 이식 할 수는 없습니다.

  • 보통 시스템은 신호 처리기에서 사용할 수있는 C 라이브러리 함수로 이루어진 비동기 신호 안전 함수 목록을 가지고 있습니다. 종종 printf 가 이러한 함수 중 하나입니다.

  • 특히 C 표준은 스레드 인터페이스 (C11 이후) 또는 POSIX 스레드와 같은 플랫폼 특정 스레드 라이브러리와의 상호 작용에 대해 많이 정의하지 않습니다. 이러한 플랫폼은 이러한 스레드 라이브러리와 신호 자체의 상호 작용을 지정해야합니다.

"signal ()"을 사용한 신호 처리

신호 번호 는 프로그램 외부에서 시작될 때 (예 : Cntrl-C 와 같은 키 누름과 같이) 프로그램 자체의 오작동 또는 비동기 ( SIGINT - 대화식주의)로 인해 트리거 될 때 동기식 ( SIGSEGV - 분할 오류와 같은) 일 수 있습니다.

signal() 함수는 ISO C 표준의 일부이며 특정 신호를 처리하는 함수를 할당하는 데 사용할 수 있습니다

#include <stdio.h>  /* printf() */
#include <stdlib.h> /* abort()  */
#include <signal.h> /* signal() */

void handler_nonportable(int sig)
{
    /* undefined behavior, maybe fine on specific platform */
    printf("Catched: %d\n", sig);
    
    /* abort is safe to call */
    abort();
}

sig_atomic_t volatile finished = 0;

void handler(int sig)
{
    switch (sig) {
    /* hardware interrupts should not return */
    case SIGSEGV:
    case SIGFPE:
    case SIGILL:
C11
      /* quick_exit is safe to call */
      quick_exit(EXIT_FAILURE);
C11
      /* use _Exit in pre-C11 */
      _Exit(EXIT_FAILURE);
    default:
       /* Reset the signal to the default handler, 
          so we will not be called again if things go
          wrong on return. */
      signal(sig, SIG_DFL);
      /* let everybody know that we are finished */
      finished = sig;
      return;
   }
}

int main(void)
{

    /* Catch the SIGSEGV signal, raised on segmentation faults (i.e NULL ptr access */
    if (signal(SIGSEGV, &handler) == SIG_ERR) {
        perror("could not establish handler for SIGSEGV");
        return EXIT_FAILURE;
    }

    /* Catch the SIGTERM signal, termination request */
    if (signal(SIGTERM, &handler) == SIG_ERR) {
        perror("could not establish handler for SIGTERM");
        return EXIT_FAILURE;
    }

    /* Ignore the SIGINT signal, by setting the handler to `SIG_IGN`. */
    signal(SIGINT, SIG_IGN);


    /* Do something that takes some time here, and leaves
       the time to terminate the program from the keyboard. */

    /* Then: */

    if (finished) {
       fprintf(stderr, "we have been terminated by signal %d\n", (int)finished);
        return EXIT_FAILURE;
    }


    /* Try to force a segmentation fault, and raise a SIGSEGV */
    {
      char* ptr = 0;
      *ptr = 0;
    }

    /* This should never be executed */
    return EXIT_SUCCESS;
}

signal() 사용하면 시그널 핸들러 내부에서 무엇을 할 수 있는지에 대한 중요한 제한이 부과됩니다. 자세한 내용은 발언을 참조하십시오.

POSIX 는 덜 특정한 동작과 중요한 구현 변화 때문에 signal() sigaction() 대신 sigaction() 사용할 것을 권장합니다. POSIX는 또한 어떤 목적 으로든 프로그래머가 자유롭게 사용할 수있는 SIGUSR1SIGUSR2 포함하여 ISO C 표준보다 더 많은 신호를 정의합니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow