2010-04-04 4 views
72

필자는 POSIX 쓰레드와 POSIX 시그널이 어떻게 상호 작용 하는지를 이해하려고 노력 해왔다. 특히, 나는 다음에 관심이있다 :POSIX 쓰레드와 시그널

  • 신호가 전달되는 스레드를 제어하는 ​​가장 좋은 방법은 무엇입니까 (처음에는 치명적이지 않다고 가정).
  • 신호가 도착한 다른 스레드 (실제로 사용 중일 수 있음)를 알려주는 가장 좋은 방법은 무엇입니까? (나는 이미 신호 처리기에서 pthread 조건 변수를 사용하는 것이 좋지 않음을 알고 있습니다.)
  • 신호가 발생한 정보를 다른 스레드로 전달하는 것을 안전하게 처리하려면 어떻게해야합니까? 신호 처리기에서이 작업이 필요합니까? (I는하지 일반적으로 다른 스레드를 죽이고 싶어 할;. 내가 훨씬 더 미묘한 접근 방식이 필요합니다)

참고로 나는이를하려는 이유, 내가 스레드를 지원하는 TclX 패키지를 변환하는 방법을 연구, 또는 해요 대해 그것을 분할하고 최소한 유용한 부분 지원 스레드를 만드십시오. 신호는 특히 중요한 부분 중 하나입니다.

답변

42
  • 신호가 전달되는 스레드 제어 할 수있는 가장 좋은 방법은 무엇입니까?

는 @ zoli2k 바와 같이, 명시 적으로 처리하려는 모든 신호 (또는 스레드 특정 신호의 책임 각각의 세트)를 처리하는 단일 스레드를 지명, 좋은 기술이다.

  • 는 신호가 도착했습니다 을 다른 스레드 (즉 실제로 사용 중일 수 있습니다)를 알 수있는 가장 좋은 방법은 무엇입니까? [...]
  • 내가 안전하게 신호 있다는 정보를 전달 처리 할 수있는 방법 다른 스레드에 발생했습니다? 신호 처리기에서이 작업이 필요합니까? 모든 스레드가 신호 마스크를 상속되도록, main에서

    블록 원하는 모든 신호 :

내가 말을하지 않습니다 "최선을"그러나 여기 내 추천합니다. 그런 다음 특수 신호 수신 스레드를 신호 구동 이벤트 루프로 설정하여 새로 도착한 신호를 다른 내부 스레드 통신으로 전달합니다.

가장 간단한 방법은 스레드가 sigwaitinfo or sigtimedwait을 사용하여 루프에서 신호를 받아들이도록하는 것입니다. 그런 다음 스레드는 신호를 어떻게 든 변환하여 아마도 pthread_cond_t을 브로드 캐스팅하고 더 많은 I/O로 다른 스레드를 깨우고 응용 프로그램 관련 스레드 안전 대기열에 명령을 대기열에 넣습니다.

또는 특수 스레드는 신호 처리기에 신호를 전달하여 신호 처리 준비가되었을 때만 전달하도록 마스크를 해제 할 수 있습니다. 그러나 핸들러를 통한 신호 전달은 sigwait 패밀리를 통한 신호 수용보다 오류가 발생하는 경향이 있습니다.이 경우 수신자의 신호 처리기는 sig_atomic_t 플래그를 설정하여 간단한 및 비동기 신호 안전 조치를 수행합니다 (sigaddset(&signals_i_have_seen_recently, latest_sig), write).() 바이트를 non-blocking self-pipe으로 보낸다. 그런 다음, 마스크 된 메인 루프로 돌아가서, 스레드는 위와 같이 다른 스레드로 신호 수신을 통신한다.

(가 바르게 sigwait 접근이 우수 있다고 지적 @caf 업데이트되었습니다.)

+0

그것은 특히 치명적이지 않은 신호 처리를 처리하는 데 사용할 수 있으므로 훨씬 더 유용한 대답입니다. 감사! –

+1

시그널 핸들링 쓰레드가 시그널 핸들러를 전혀 설치하지 않으면, 대신'sigwaitinfo()'(또는'sigtimedwait()')를 반복하고, 설명 된대로 나머지 어플리케이션에 디스패치합니다 마지막 단락에서. – caf

+0

@caf, 실제로 그렇게. 업데이트 됨 – pilcrow

13

POSIX 표준에 따르면 모든 스레드는 시스템에서 동일한 PID로 나타나야하며 pthread_sigmask()을 사용하면 모든 스레드에 대해 신호 차단 마스크를 정의 할 수 있습니다.

PID 당 하나의 신호 처리기 만 정의 할 수 있으므로 하나의 스레드에서 모든 신호를 처리하고 실행중인 스레드를 취소해야하는 경우 pthread_cancel()을 전송하는 것이 좋습니다. pthread_kill()에 대해 선호되는 방법이므로 스레드에 대한 정리 기능을 정의 할 수 있습니다.

일부 오래된 시스템에서는 적절한 커널 지원이 없기 때문에 실행중인 스레드가 상위 스레드의 PID와 다른 PID를 가질 수 있습니다. 신호 처리에 대한 FAQ는 linuxThreads on Linux 2.4을 참조하십시오.

내가 지금까지에있어
+0

"구현 된"무엇을 의미합니까? 또한, 시그널 (SIGHUP과 SIGWINCH는 더 세밀 함이 필요함)에 대한 응답으로 다른 쓰레드를 항상 누스하는 것은 옳지 않지만 다른 쓰레드가 알 수 있도록 조건 변수를 사용하는 것은 안전하지 않습니다. 불쌍한 대답. –

+0

@Donal Fellows> 포스트가 수정되었습니다. 나는 그것이 지금 더 도움이되기를 바랍니다. – zoli2k

+1

다운 투표를 삭제했는데 신호에 대한 응답으로 스레드를 죽일 수 없기 때문에 여전히 충분한 대답이 아닙니다. 어떤 경우에는 응답을 로컬로 대기시키는 이벤트를 진행할 것이고, 다른 것들은 스레드를 매우 조심스럽게 찢어 버릴 수 있습니다. (BTW, 이미 그러한 부분을 수행 할 수있는 대부분의 기계가 있으며, OS 신호가 누락되었습니다). –

3

:

  • 신호 중 일부는 일반적으로 단지 과정 어쨌든 (SIGILL를) 죽일해야 다른 주요 클래스에 와서 그 중 일부는 결코 아무것도 (SIGIO을하고 필요하지, 쉽게 어쨌든 비동기 IO를 수행하는 것). 이 두 클래스는 아무런 조치가 필요 없습니다.
  • 일부 신호는 즉시 처리 할 필요가 없습니다. SIGWINCH의 좋아하는 것들이 편리 할 때까지 대기 할 수 있습니다 (X11의 이벤트와 마찬가지입니다).
  • 까다로운 것들은 당신이하고있는 일을 방해함으로써 그들에게 반응하기를 원하지만 실을 닦아내는 범위까지 가지 않고 있습니다. 특히, 대화 형 모드의 SIGINT는 응답을 남겨 두어야합니다.

나는 여전히 통해 정렬 할 수있어 signal, sigactionpselect, sigwait, sigaltstack, 그리고 다른 비트와 POSIX (비 POSIX) API 조각의 전체 무리.

4

IMHO, 유닉스 V 신호와 POSIX 쓰레드 잘 혼합하지 않습니다. 유닉스 V는 1970 년이다.

취소 점이있다. 하나의 응용 프로그램에서 신호와 pthread를 허용하면 궁극적으로 EINTR을 반환 할 수있는 루프마다 루프를 작성하게된다.

그래서 Linux 나 QNX에서 멀티 스레드 프로그래밍을해야했던 (몇 ​​가지) 경우에서 모든 스레드 (모든 스레드)에 대한 모든 신호를 마스크 처리했습니다.

Unix V 시그널이 도착하면, 프로세스는 스택을 전환합니다 (프로세스 내에서 얻을 수있는만큼의 동시성이 유닉스 V에서있었습니다).

다른 게시물에서 알 수 있듯이 현재 어떤 POSIX 스레드가 스택 전환의 피해자가 될지 시스템에 알릴 수 있습니다.

신호 처리기 스레드를 작동 시키면 신호 정보를 문명화 된 방법으로 변환하고 다른 스레드에서 사용할 수있는 방법이 남아 있습니다. 스레드 간 통신을위한 인프라가 필요합니다. 하나의 패턴은 액터 패턴이 유용합니다. 각 스레드는 일부 진행중인 메시징 메커니즘의 대상입니다.

그래서 다른 스레드를 취소하거나 죽이는 대신 (또는 다른 별난 것들) 신호 컨텍스트의 신호를 신호 처리기 스레드로 마샬링하고 액터 패턴 통신 메커니즘을 사용하여 의미 론적으로 유용한 메시지를 보내야합니다 신호 관련 정보를 필요로하는 배우에게.