POSIX 스레드 및 신호


81

POSIX 스레드와 POSIX 신호가 상호 작용하는 방식의 복잡성을 이해하려고 노력해 왔습니다. 특히 다음 사항에 관심이 있습니다.

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

내가 이것을 원하는 이유에 대한 참조를 위해 TclX 패키지를 스레드를 지원 하도록 변환 하거나 분할하고 적어도 유용한 부분이 스레드를 지원하도록 만드는 방법을 연구 하고 있습니다. 신호는 특히 흥미로운 부분 중 하나입니다.

답변:


48
  • 신호가 전달되는 스레드를 제어하는 ​​가장 좋은 방법은 무엇입니까?

@ zoli2k가 지적했듯이, 처리하고자하는 모든 신호를 처리 할 단일 스레드 (또는 특정 신호 책임이있는 스레드 세트)를 명시 적으로 지정하는 것은 좋은 기술입니다.

  • 신호가 도착했음을 다른 스레드 (실제로 사용 중일 수 있음)에게 알리는 가장 좋은 방법은 무엇입니까? [...]
  • 신호가 발생했다는 정보를 다른 스레드로 전달하는 것을 어떻게 안전하게 처리 할 수 ​​있습니까? 이것이 신호 처리기에서 발생해야합니까?

"최고"라고 말하지 않겠습니다.하지만 여기에 권장 사항이 있습니다.

main모든 스레드가 해당 신호 마스크를 상속하도록 에서 원하는 모든 신호를 차단합니다 . 그런 다음 특수 신호 수신 스레드를 신호 구동 이벤트 루프로 만들어 새로 도착한 신호를 다른 스레드 내 통신으로 전달합니다. 합니다.

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

또는 특수 스레드를 사용하면 신호를 처리 할 준비가 된 경우에만 전달을 위해 마스크를 해제하여 신호 처리기에 신호를 전달할 수 있습니다. (처리기를 통한 신호 전달은 sigwait패밀리 를 통한 신호 수용보다 오류가 더 발생하기 쉽습니다 .)이 경우 수신자의 신호 처리기는 sig_atomic_t플래그 설정 , 호출 sigaddset(&signals_i_have_seen_recently, latest_sig), write() 바이트 와 같은 간단한 비동기 신호 안전 작업을 수행합니다. 비 - 블로킹 자기 파이프 등 그리고, 다시 메인 마스크 루프 스레드는 상기 다른 스레드에 신호의 수신을 통신한다.

( 업데이트 @caf는 sigwait접근 방식이 우수하다는 것을 올바르게 지적합니다 .)


1
특히 치명적이지 않은 신호 처리에도 사용할 수 있으므로 훨씬 더 유용한 답변입니다. 감사!
Donal Fellows

1
시그널 처리 스레드가 시그널 핸들러를 전혀 설치하지 않는 것이 가장 쉽습니다. 대신에 sigwaitinfo()(또는 sigtimedwait()) 루프를 돌고 마지막 단락에서 설명한대로 나머지 애플리케이션으로 디스패치합니다.
caf

@caf, 정말 그렇습니다. 업데이트
pilcrow

14

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

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

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


"구현"이란 무엇을 의미합니까? 또한 신호에 대한 응답으로 다른 스레드를 항상 핵으로 처리하는 것은 정확하지 않지만 (SIGHUP 및 SIGWINCH는 더 세밀 함이 필요함) 다른 스레드에 알리기 위해 조건 변수를 사용하는 것은 안전하지 않습니다. 잘못된 대답입니다.
Donal Fellows

1
내 다운 투표를 제거했지만 신호에 대한 응답으로 스레드를 죽일 수 없기 때문에 여전히 충분한 대답이 아닙니다. 어떤 경우에는 응답으로 이벤트를 로컬로 대기열에 넣을 것이고, 다른 경우에는 스레드를 매우 조심스럽게 해체해야합니다 (BTW, 이미 이러한 부분을 수행 할 수있는 대부분의 기계가 있습니다. OS에 대한 연결입니다. 누락 된 신호).
Donal Fellows

1
@ zoli2k : 최근 make menuconfig에 uClibc의 새로 복제 된 git master 브랜치로 실행 을 시도했습니다 . 거기에 있다 2012 여전히 NPTL을 선택에 대한 권장 해 같은 오래된 리눅스 쓰레드와 POSIX 스레드 구현과 새로운 NPTL하지만, 도움이 사이에 선택. 따라서 최신 임베디드 Linux 시스템에서는 시스템이 최신 Linux 커널을 실행하고 있더라도 사용되지 않는 LinuxThreads 구현을 보는 것이 일반적입니다.
FooF

3

지금까지 내가있는 곳 :

  • 신호는 다른 주요 클래스로 제공되며, 그중 일부는 일반적으로 어쨌든 프로세스를 종료해야하며 (SIGILL) 일부는 아무것도 할 필요가 없습니다 (SIGIO, 어쨌든 비동기 IO를 수행하는 것이 더 쉽습니다). 이 두 클래스는 조치가 필요하지 않습니다.
  • 일부 신호는 즉시 처리 할 필요가 없습니다. SIGWINCH와 같은 것은 편리 할 때까지 대기열에 넣을 수 있습니다 (X11의 이벤트처럼).
  • 까다로운 것들은 당신이하는 일을 방해하지만 스레드를 지우지 않고 그들에게 응답하고 싶은 것입니다. 특히, 대화 형 모드의 SIGINT는 반응 형을 유지해야합니다.

나는 아직도를 통해 정렬 할 수있어 signalsigaction, pselect, sigwait, sigaltstack, 등의 비트와 POSIX (비 POSIX) API 조각의 전체 무리.


3

IMHO, Unix V 신호 및 posix 스레드는 잘 섞이지 않습니다. Unix V는 1970입니다. POSIX는 1980입니다.

취소 지점이 있으며 하나의 응용 프로그램에서 신호와 pthread를 허용하면 결국 각 호출 주위에 루프를 작성하게되어 놀랍게도 EINTR을 반환 할 수 있습니다.

그래서 내가 리눅스 나 QNX에서 멀티 스레드를 프로그래밍해야하는 (몇 안되는) 경우에서 한 것은 모든 (그러나 하나의) 스레드에 대한 모든 신호를 마스킹하는 것입니다.

Unix V 신호가 도착하면 프로세스는 스택을 전환합니다 (즉, 프로세스 내에서 얻을 수있는만큼 Unix V의 동시성).

여기에있는 다른 포스트가 암시 하듯이, 어떤 posix 스레드가 해당 스택 전환의 희생자가 될 것인지 시스템에 알릴 수 있습니다.

일단 시그널 핸들러 스레드가 작동하도록 관리하면 시그널 정보를 문명화 된 것으로 변환하는 방법, 다른 스레드가 사용할 수있는 방법에 대한 질문이 남아 있습니다. 스레드 간 통신을위한 인프라가 필요합니다. 유용한 한 가지 패턴은 액터 패턴입니다. 여기서 각 스레드는 프로세스 내 메시징 메커니즘의 대상이됩니다.

따라서 다른 스레드를 취소하거나 그것들 (또는 다른 이상한 것들)을 죽이는 대신 Signal 컨텍스트에서 Signal 핸들러 스레드로 Signal을 마샬링 한 다음 액터 패턴 통신 메커니즘을 사용하여 의미 론적으로 유용한 메시지를 해당 액터에게 보내야합니다. 신호 관련 정보가 필요한 사람.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.