일반적으로 multi-thread 환경에서는 signal을 잘 사용하지 않지만, 불가피하게 signal을 사용하게 되는 경우가 생길 수 있다. 하지만 signal의 특성상 signal은 특정 process를 지정해서 보내는 것이지 특정 thread로 전달되는 것이 아니기 때문에 process 내의 어떤 thread에서 signal을 받아 처리할지 모른다. 예를 들어 main thread와 thread1, thread2가 있다고 가정하면 main thread에서 signal handler를 지정하더라도, signal handler에서 처리되지 않고, thread1 혹은 thread2로 signal이 전달될 수 있다. 그러므로 이 경우에는 다음 그림과 같은 특별한 처리가 필요하다.
그림에 관해서 간략히 설명하겠다. 먼저 main thread에서 pthread_sigmask API를 이용해 SIGINT를 제외한 모든 signal을 mask시킨다. 다음으로 signal processing 전용 thread와 그 외의 worker thread를 생성한다. signal processing 전용 thread에서는 sigwait API를 이용해 수신하고자하는 signal만 수신한다. 그 외의 worker thread들은 자신들을 생성한 main thread의 signal mask속성을 그대로 따라가므로 signal 수신없이 정상적으로 작업을 수행할 수 있다. 이 때 유의할 사항은 main thread에서 반드시 signal mask 설정을 한 뒤, worker thread를 생성해야 한다.
다음의 코드는 위의 그림을 간략하게 구현한 것이다. 코드 속의 signal processing thread는 startSigThread, worker thread는 startThread이다. 설명은 코드 속의 주석을 참조하기 바란다. 해당 코드 컴파일 후, 실행한 뒤,
kill -SIGUSR1 pid
와 같은 방식으로 명령을 실행하면, signal handler함수가 호출될 것이다. linux에서 컴파일해본 경험이 없다면 첨부파일을 참조하기 바란다.
multithread_signal.c |
#include <stdio.h> #define NUM_THREADS 3
void *startSigThread(void*); // signal processing thread func void cleanThread(thread_args* tArgs); // thread 종료 담당 thread_args tThreadArgs[NUM_THREADS] = { int main() //signal set setting 및 sigmask // thread 들 생성 // thread 종료 return 0; void *startSigThread(void* pArgs) printf("* Start signal thread (tid = %lu)\n", (long)pthread_self()); } void *startThread(void* pArgs) void cleanThread(thread_args* pArgs) for(i = 0; i < NUM_THREADS; i++) void sa_handler_usr(int nSigNum) |
코드 출처 : advanced 리눅스 시스템 네트워크 프로그래밍(2판)