2008-10-23 2 views
104

여기에있는 앱에 여분의 신호 처리기를 추가하려고했는데 작성자가 다른 신호 처리기를 설정하는 데 sigaction을 사용했음을 알았습니다. 나는 신호를 사용하려고했다. 컨벤션을 따르려면 나는 sigaction을 사용해야합니다.하지만 처음부터 글을 쓰고 있다면 어떤 것을 선택해야합니까?sigaction과 signal의 차이점은 무엇입니까?

답변

124

사용하지 않으려는 강력한 이유가없는 한 sigaction()을 사용하십시오.

signal() 인터페이스는 그 자체로 선호도가 오래된 (따라서 가용성이 있음) C 표준에 정의되어 있습니다. 그럼에도 불구하고 sigaction()이 명시 적으로 추가 한 플래그를 사용하여 정확하게 이전의 signal() 동작을 시뮬레이트하도록 허용하지 않는 한 여러 가지 바람직하지 않은 특성이 있습니다 (예 : sigaction()).

  1. signal() 함수는 현재 처리기가 실행되는 동안 다른 신호가 도착하는 것을 (필연적으로) 차단하지 않습니다. sigaction()은 현재 처리기가 반환 할 때까지 다른 신호를 차단할 수 있습니다.
  2. signal() 기능은 대개 거의 모든 신호에 대해 신호 동작을 SIG_DFL (기본값)으로 다시 설정합니다. 즉, signal() 처리기가 첫 번째 작업으로 자체를 다시 설치해야 함을 의미합니다. 또한 신호가 감지되고 핸들러가 다시 설치되는 동안 신호의 두 번째 인스턴스가 도착하면 기본 동작 (보통 종료, 때로는 편견 - 코어 덤프라고도 함) 사이의 취약성 창이 열립니다.
  3. signal()의 정확한 동작은 시스템마다 다르며 표준은 이러한 변형을 허용합니다.

이들은 sigaction()를 사용하는 대신 signal()에 대한 일반적으로 좋은 이유가 있습니다. 그러나 sigaction()의 인터페이스는 분명히 더 까다 롭습니다. 사용하는 두 가지의

하든는 다른 신호 인터페이스 등 sighold(), sigignore(), sigpause()sigrelse() 유혹 할 수 없습니다. 그들은 대체로 sigaction()의 대안이지만, 이들은 간신히 표준화되어 있으며 심각한 사용보다는 하위 호환성을 위해 POSIX에 존재합니다. POSIX 표준에 따르면 다중 스레드 프로그램에서의 동작은 정의되지 않았습니다.

멀티 스레드 프로그램과 신호는 완전히 다른 복잡한 이야기입니다. AFAIK, signal()sigaction()은 멀티 스레드 응용 프로그램에서 정상입니다.

Cornstalksobserves :

signal()의 리눅스 매뉴얼 페이지 말한다 : 다중 스레드 프로세스에서 signal()

  효과는 지정되지 않습니다.

그러므로 나는 sigaction()이 멀티 스레드 프로세스에서 안전하게 사용될 수 있다고 생각합니다.

재미 있습니다. 이 경우 Linux 매뉴얼 페이지는 POSIX보다 더 제한적입니다. POSIX는 signal() 위해 지정

  • abort()를 호출하는 공정 : 처리는 다중 스레드

    경우 프로세스는 단일 스레드하고 있으면, 신호 처리기 이외의 결과로서 다른 실행될 , raise()kill()pthread_kill() 또는 sigqueue()

  • 는 보류 신호가 블록화되고 그것이
  • ,536,913,632를 리턴 차단 해제 호출하기 전에 전달되고 차단되지 않은 신호를 생성하도록 10

신호 처리기가 volatile sig_atomic_t으로 선언 된 개체에 값을 할당하는 것 이외의 정적 저장소 기간이있는 errno 이외의 개체를 참조하거나 신호 처리기가이 표준에 정의 된 함수를 호출하는 경우 동작이 정의되지 않습니다. Signal Concepts에 나열된 함수 중 하나보다

따라서 POSIX는 멀티 스레드 응용 프로그램에서 signal()의 동작을 명확하게 지정합니다.

그럼에도 불구하고 본질적으로 모든 상황에서 sigaction()이 바람직하며 이동식 멀티 스레드 코드는 sigaction()을 사용해야합니다. ("표준 C에서 정의한 기능 만 사용"- 예 , C11 코드는 멀티 스레드 가능). 기본적으로이 대답의 첫 단락도 말합니다.

+9

'signal '에 대한이 설명은 실제로 Unix System V 동작입니다. POSIX는이 동작이나 훨씬 더 정교한 BSD 동작을 허용하지만 어느 것을 얻을지 확신 할 수 없기 때문에 여전히'sigaction'을 사용하는 것이 가장 좋습니다. –

+1

이전의 signal() 비헤이비어를 충실하게 시뮬레이트하기 위해 sigaction()에 명시 적으로 추가 된 플래그를 사용하지 않는 한. 그것들은 어떤 플래그일까요? – ChristianCuevas

+0

@AlexFritz : 주로'SA_RESETHAND', 또한'SA_NODEFER'. –

2

적어도 이론적으로는 더 휴대하기 때문에 signal()을 사용합니다. 필자는 POSIX 호환 레이어가없고 signal()을 지원하는 현대 시스템을 제안 할 수있는 주석 작성자에게 투표합니다. GLIBC documentation에서 인용

:

그것은 단일 프로그램 내에서 신호은 sigaction 두 기능을 사용하는 것이 가능하지만, 당신은 그들이 약간 이상한 방법을의 상호 작용을 할 수 있기 때문에주의해야합니다.

sigaction 함수는 함수보다 많은 정보를 지정하므로 signal의 반환 값은 범위의 sigaction 가능성을 나타낼 수 없습니다. 따라서 에 신호를 저장하고 나중에 조치를 다시 설정하면 은 sigaction으로 설정 한 처리기를 올바르게 다시 설정하지 못할 수 있습니다.

결과적으로 문제가 발생하지 않도록하려면 항상 sigaction을 사용하여 을 저장하고 프로그램에서 sigaction을 전혀 사용하지 않으면 처리기를 복원하십시오. sigaction이 더 일반적이므로 원래 신호 또는 sigaction으로 설정되었는지 여부에 관계없이 작업을 적절하게 저장하고 다시 설정할 수 있습니다.

일부 시스템에서는 신호가있는 동작을 설정 한 다음 을 sigaction으로 검사하면 수신 한 처리기 주소가 과 같지 않을 수 있습니다. 신호가있는 액션 인수로 사용하기에 적합한 이 아닐 수도 있습니다. 그러나 당신은 을 sigaction의 인자로 사용할 수 있습니다. 이 문제는 결코 GNU 시스템에서 발생하지 않습니다.

따라서 하나의 프로그램 내에서 메커니즘 중 하나 또는 다른 것을 일관되게 사용하는 것이 좋습니다.

휴대 성 노트 : 기본 신호 기능은 ISO C의 특징 인 이며 sigaction은 POSIX.1 표준의 일부입니다. 이 POSIX가 아닌 시스템으로의 이식성에 관심이 있다면 대신 signal 함수를 사용해야합니다.

저작권 (C)

권한은 복사, 배포 및/또는 GNU 자유 문서 사용 허가서의 규정에 따라 본 문서를 개작 재단, 주식 1996-2008 자유 소프트웨어, 버전 1.2 또는 자유 소프트웨어가 발행 한 이후 버전 재단; 불변 부분이없고, 앞 표지 문이 없으며, 과 뒷 표지문이 없습니다. 라이선스 사본은 "GNU Free Documentation License"섹션에 포함되어 있습니다.signal(3) 사람 페이지에서

2

:

설명

This signal() facility is a simplified interface to the more 
general sigaction(2) facility. 

모두 동일한 기본 기능을 호출합니다. 당신은 아마도 양쪽 모두 단일 신호로 응답을 조작해서는 안되지만 그것들을 섞어서 어떤 것도 끊어서는 안됩니다. ...

+0

그건 내 man 페이지에 없습니다! "signal() 시스템 호출은 숫자 signum을 가진 신호를위한 새로운 시그널 핸들러를 설치합니다."_useful_ 맨 페이지 패키지로 업그레이드해야합니다. – MattSmith

+1

Mac OS X 10.5 페이지에서 제외되었습니다. – dmckee

+0

또한 glibc의 소스 코드에서 확인되었습니다. signal()은 단지 sigaction()을 호출한다. – bmdhacks

5

OS의 신호 설비를위한 다른 인터페이스입니다. signal()이 구현 정의 (종종 경주하기 쉬운) 행동을하고 Windows, OS X, Linux 및 기타 UNIX 시스템에서 다르게 동작하므로 sigaction을 사용하여 신호를 보내는 것이 더 바람직합니다.

자세한 내용은 security note을 참조하십시오.

+0

나는 glibc 소스 코드를 보았고 signal()은 sigaction()을 호출했다. MacOS 매뉴얼 페이지에서도 같은 것을 주장하는 위의 내용을 참조하십시오. – bmdhacks

+0

알아두면 좋습니다. 나는 시그널 핸들러가 종료 전에 깔끔하게 닫는 것을 보았을 뿐이므로 보통 핸들러를 다시 설치하는 것에 의존하지는 않는다. – MattSmith

4

은 나에게,이 아래 라인은 결정에 충분했다 :

은 sigaction() 함수는 신호를 제어하기위한 보다 포괄적이고 신뢰할 수있는 메커니즘을 제공합니다; 당신은 처음부터 시작하거나 이전 프로그램을 수정하든 새로운 응용 프로그램은 sigaction() 보다는 신호()

http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html#tag_03_690_07

를 사용해야은 sigaction 오른쪽 옵션이어야한다.

1

신호()는 표준 C이며 sigaction()은 표준이 아닙니다.

POSIX 시스템을 사용하고 있다면 둘 중 하나를 사용할 수 있다면 sigaction()을 사용하십시오. signal()이 핸들러를 다시 설정하는지, 즉 핸들러 내부에서 signal()을 다시 호출해야하는지 여부는 지정되지 않습니다. 더 나쁜 것은 경주가 있다는 것입니다 : 핸들러를 다시 설치하기 전에 두 신호가 빠르게 연속해서 전달되고 두 번째 신호가 전달되면 기본 작업이 수행되며 프로세스가 종료 될 수 있습니다. 반면에 sigaction()은 "신뢰할 수있는"신호 의미론을 사용하도록 보장됩니다. 핸들러는 재설치되지 않으므로 다시 설치할 필요가 없습니다. SA_RESTART를 사용하면 자동으로 다시 시작되도록 시스템 호출을 얻을 수도 있습니다 (수동으로 EINTR을 확인할 필요가 없습니다). sigaction()에는 더 많은 옵션이 있으며 신뢰할 수 있으므로 사용하는 것이 좋습니다.

Psst ... 내가 말했지 만 POSIX에는 현재 signal()과 같은 역할을하지만 BSD 의미론을 제공하는 bsd_signal() 함수가 있습니다. 이는 안정적이라는 것을 의미합니다. 주 용도는 신뢰할 수있는 신호를 사용하는 오래된 응용 프로그램을 포팅하는 것이고 POSIX는이를 사용하지 않는 것이 좋습니다.

1

또한 signal()을 통해 sigaction()을 사용하는 것이 좋습니다. 한 점 더 추가하고 싶습니다. sigaction()은 죽은 프로세스의 pid와 같은 더 많은 옵션을 제공합니다 (siginfo_t 구조체를 사용하여 가능).

관련 문제