Namespaces
Variants

std:: signal

From cppreference.net
Utilities library
헤더 파일에 정의됨 <csignal>
/* signal-handler */ * signal ( int sig, /* signal-handler */ * handler ) ;
(1)
extern "C" using /* signal-handler */ = void ( int ) ;
(2) ( exposition only* )

시그널 sig 의 처리를 변경합니다. handler 에 따라 시그널을 무시하거나, 기본값으로 설정하거나, 사용자 정의 함수로 처리할 수 있습니다.

시그널 핸들러가 함수로 설정되고 시그널이 발생할 때, 시그널 핸들러 시작 전에 std :: signal ( sig, SIG_DFL ) 가 즉시 실행되는지는 구현에 따라 정의됩니다. 또한 구현은 시그널 핸들러가 실행되는 동안 일부 구현 정의된 시그널 집합이 발생하는 것을 방지할 수 있습니다.

일부 시그널에 대해서는 구현체가 프로그램 시작 시 std :: signal ( sig, SIG_IGN ) 를 호출할 수 있습니다. 나머지 시그널에 대해서는 구현체가 반드시 std :: signal ( sig, SIG_DFL ) 를 호출해야 합니다.

(참고: POSIX는 이러한 구현 정의 동작들을 표준화하기 위해 sigaction 을 도입했습니다)

목차

매개변수

sig - 시그널 핸들러를 설정할 시그널. 구현에서 정의된 값이거나 다음 값 중 하나일 수 있습니다:
시그널 타입을 정의함
(매크로 상수)
handler - 시그널 핸들러. 다음 중 하나여야 합니다:
  • SIG_DFL 매크로. 시그널 핸들러가 기본 시그널 핸들러로 설정됩니다.
  • SIG_IGN 매크로. 시그널이 무시됩니다.
  • 함수에 대한 포인터. 함수의 시그니처는 다음과 동일해야 합니다:
extern "C" void fun ( int sig ) ;


반환값

성공 시 이전 시그널 핸들러 또는 SIG_ERR 반환 (일부 구현에서는 시그널 핸들러 설정이 비활성화될 수 있음).

시그널 핸들러

사용자 정의 함수가 시그널 핸들러로 설치될 때 다음과 같은 제한 사항이 적용됩니다.

시그널 핸들러가 std::abort std::raise 의 결과로 호출되지 않은 경우(비동기 시그널), 다음 중 하나라도 해당되면 동작은 정의되지 않습니다:

  • 시그널 핸들러가 표준 라이브러리 내의 어떤 함수를 호출하는 경우, 다음은 제외:
  • std::abort
  • std::_Exit
  • std::quick_exit
  • std::signal (첫 번째 인자가 현재 처리 중인 시그널 번호인 경우. 비동기 핸들러는 자기 자신을 재등록할 수 있지만 다른 시그널은 안 됨)
  • 시그널 핸들러가 정적 저장 기간을 가진 객체를 참조하는 경우, 그 객체가 std::atomic 이거나 (C++11부터) volatile std:: sig_atomic_t 가 아닌 경우
(C++17 이전)

단순 락프리 원자 연산 <atomic> 또는 <stdatomic.h> (C++23부터) 의 함수 f 의 호출로서, 다음 조건을 만족합니다:

어떤 시그널 핸들러가 다음 중 어떤 것을 수행하면 동작은 정의되지 않습니다:

  • 어떤 라이브러리 함수를 호출하는 경우, 단순 락프리 원자 연산과 다음 시그널-안전 함수들은 제외(특히 동적 할당은 시그널-안전이 아님):
  • 스레드 저장 기간을 가진 객체에 접근하는 경우
  • dynamic_cast 표현식
  • throw 표현식
  • try 블록 진입
  • 정적 변수의 초기화가 동적 비지역 초기화 를 수행하는 경우(첫 ODR-사용까지 지연되는 경우 포함)
  • 다른 스레드가 동시에 초기화하는 정적 저장 기간 변수의 초기화 완료를 기다리는 경우
(C++17부터)

사용자 정의 함수가 SIGFPE , SIGILL , SIGSEGV 또는 계산 예외를 지정하는 다른 구현 정의 시그널을 처리하는 동안 반환되면, 동작은 정의되지 않습니다.

시그널 핸들러가 std::abort 또는 std::raise (동기식 시그널)의 결과로 호출된 경우, 시그널 핸들러가 std::raise 를 호출하면 그 동작은 정의되지 않습니다.

시그널 핸들러 진입 시, 부동 소수점 환경 의 상태와 모든 객체의 값은 다음을 제외하고는 지정되지 않는다:

(C++11부터)

시그널 핸들러에서 반환될 때, 시그널 핸들러에 의해 수정된 객체 중 volatile std:: sig_atomic_t 또는 lock-free std::atomic 이 아닌 객체의 값은 불확정적이다.

(C++14 이전)

signal() 함수 호출은 결과적으로 발생하는 시그널 핸들러의 호출과 동기화된다 .

시그널 핸들러가 std::raise 호출의 결과로 (동기적으로) 실행되는 경우, 핸들러의 실행은 std::raise 호출 이후에 순서화되고 , 그 반환 이전에 순서화되며 , std::raise 와 동일한 스레드에서 실행된다. 다른 시그널에 대한 핸들러 실행은 프로그램의 나머지 부분과 관련하여 순서화되지 않으며 , 지정되지 않은 스레드에서 실행된다.

volatile std:: sig_atomic_t 타입의 동일한 객체에 대한 두 접근이 동일한 스레드에서 발생하면, 하나 이상이 시그널 핸들러 내에서 발생하더라도 데이터 경쟁이 발생하지 않는다. 각 시그널 핸들러 호출에 대해, 시그널 핸들러를 호출하는 스레드가 수행한 평가는 A와 B 두 그룹으로 나눌 수 있으며, B의 평가가 A의 평가보다 먼저 발생하지 않으며 , 이러한 volatile std:: sig_atomic_t 객체의 평가는 A의 모든 평가가 시그널 핸들러 실행보다 먼저 발생하고 , 시그널 핸들러 실행이 B의 모든 평가보다 먼저 발생한 것처럼 값을 취한다.

(C++14부터)

참고 사항

POSIX는 signal 이 thread-safe해야 하며, 모든 signal handler에서 호출될 수 있는 async-signal-safe 라이브러리 함수 목록을 명시합니다 .

시그널 핸들러는 C 링크age 를 가질 것으로 예상되며, 일반적으로 C와 C++의 공통 부분집합 기능만 사용해야 합니다. 그러나 일반적인 구현에서는 C++ 링크age를 가진 함수가 시그널 핸들러로 사용되는 것을 허용합니다.

예제

#include <csignal>
#include <iostream>
namespace
{
    volatile std::sig_atomic_t gSignalStatus;
}
void signal_handler(int signal)
{
    gSignalStatus = signal;
}
int main()
{
    // 시그널 핸들러 설치
    std::signal(SIGINT, signal_handler);
    std::cout << "SignalValue: " << gSignalStatus << '\n';
    std::cout << "Sending signal: " << SIGINT << '\n';
    std::raise(SIGINT);
    std::cout << "SignalValue: " << gSignalStatus << '\n';
}

가능한 출력:

SignalValue: 0
Sending signal: 2
SignalValue: 2

참조문헌

  • C++23 표준 (ISO/IEC 14882:2024):
  • 17.13.5 시그널 핸들러 [support.signal]
  • C++20 표준(ISO/IEC 14882:2020):
  • 17.13.5 시그널 핸들러 [support.signal]
  • C++17 표준(ISO/IEC 14882:2017):
  • 21.10.4 시그널 핸들러 [support.signal]

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
LWG 3756 C++17 std::atomic_flag 가 시그널 안전(signal-safe)한지 여부가 불명확했음 시그널 안전함

참고 항목

특정 시그널에 대한 시그널 핸들러를 실행함
(함수)
동일 스레드에서 실행되는 스레드와 시그널 핸들러 간의 펜스
(함수)
C 문서 for signal