다중 스레드 프로그램을 설계할 때 고려해야 할 몇 가지 문제들을 살펴보자
[Fork() 및 Exec 시스템 콜]
만일 한 프로그램의 스레드가 fork()를 호출하면 새로운 프로세스는 모든 스레드를 복제해야 하는가 아니면 한 개의 스레드만 가지는 프로세스여야 할까? UNIX기종은 이 두 가지 버전 fork()를 모두 제공한다.
exec()의 경우 시스템 콜을 하면 exec()의 매개변수로 저장된 프로그램이 모든 스레드를 포함한 전체 프로세스를 대체시킨다.
응용 프로그램에 따라 어떤 fork()를 선택할 지 정해진다. fork()를 한 후 exec() 시스템 콜을 호출한다면 모든 스레드를 다 복제해서 만들어주는 것은 불필요하다. 이런 경우에는 fork() 시스템 콜을 호출한 스레드만 복사해주는 것이 적절한다. 그러나 새 프로세스가 fork()후 exec를 하지 않는다면 새 프로세스는 모든 스레드들을 복제 해야한다.
[신호 처리]
신호는 UNIX에서 프로세스에 어떤 이벤트가 일어났음을 알려주기 위해 사용된다.
신호는 알려줄 이벤트의 근원지나 이유에 따라 동기식 또는 비동기식으로 전달될 수 있다.
과정은 다음과 같다.
1 ) 특정 이벤트가 일어나면 신호가 생성된다.
2 ) 생성된 신호가 프로세스에 전달된다.
3 ) 신호가 전달되면 반드시 처리되어야 한다.
모든 신호는 둘 중 하나의 처리기에 의해 처리된다.
1 ) 디폴트 신호 처리기 - 커널이 실행
2 ) 사용자 정의 신호 처리기
단일 스데르 프로그램에서는 신호 처리는 매우 간단하다. 신호는 항상 프로세스에 전달된다. 하지만 다중 스레드 프로그램에서의 신호 처리는 복잡하다. 어느 스레드에 신호를 전달해야 하는가?
신호를 전달하는 방법은 신호의 유형에 따라 다르다. 예를 들면 동기식 신호는 그 신호를 야기한 스레드에 전달되어야 한다. 비동기식 신호의 경우는 명확하지 않다. Ctrl + c 같은 키를 쳐서 그 프로세스를 강제 종료하는 신호와 같은 어떤 비동기식 신호는 그 프로세스 내 모든 스레드에 전달되어야 한다.
신호를 전달하는데 사용되는 표준 UNIX함수
kill(pid_t pid, int signal)
windows에서는 특정 신호 처리 함수를 제공하지 않는다.
하지만, 비동기식 프로시저 호출 (APC)를 이용하여 대리 실행할 수 있다.
[스레드 취소]
스레드가 데이터베이스를 병렬로 검색하고 있다가 그 중 한 스레드가 결과를 찾은 경우를 생각해보자. 병렬로 실행되던 나머지 스레드는 취소되어도 된다. 이처럼 스레드가 끝나기 전에 그것을 강제 종료시키는 작업을 스레드 취소라고 한다.
취소되어야 할 스레드를 목적 스레드라고 하는데 취소는 2가지 방식으로 이루어진다.
1 ) 비동기식 취소 : 한 스레드가 즉시 목적 스레드를 강제 종료시킨다.
2 ) 지연 취소 : 목적 스레드가 주기적으로 자신이 강제 종료되어야 할지를 점검한다.
Pthreads에서는 pthread_cancel()함수를 사용하여 스레드를 취소할 수 있다.
pthread_t tid;
//thread생성하기
pthread_create(&tid, 0, worker, NULL);
//thread취소하기
pthread_cancel(tid);
//스레드 제거 기다리기
pthread_join(tid, NULL);
Pthreads는 3가지 취소 모드를 지원한다.
1 ) off
2 ) 지연 (디폴트) -스레드가 취소 점에 도달한 경우에만 취소가 발생한다.
3 ) 비동기식
취소 점을 설정하는 한 가지 방법은 pthread_testcancel()함수를 호출하는 것이다. 취소 요청이 보류 중인 것으로 확인되면 pthread_testcancel()이 복귀하지 않고 스레드가 종료된다. 스레드를 종료시키면 할당 된 자원을 모두 반환 받기 어려울 수 있는데 이 때 정리 핸들러라고 하는 함수가 호출되게 할 수 있다.
자바의 경우 interrupt()메소드를 호출하여 대상 스레드의 인터럽트 상태를 true로 설정한다.
스레드는 자신의 인터럽트 상태를 isInterrupted()메소드를 호출하여 확인할 수 있으며 이 메소드는 스레드의 인터럽트 상태를 나타내는 부울 값을 반환한다.
[스레드-로컬 저장장치]
한 프로세스에 속한 스레드들은 그 프로세스의 데이터를 모두 공유한다. 그러나 상황에 따라서 각 스레드가 자기만 액세스할 수 있는데이터를 가져야 할 필요도 있다. 이러한 데이터를 스레드-로컬 저장장치(TLS)라고 부른다. 전역변수와 성격이 비슷하다.
[스케줄러 액티베이션]
스레드 라이브러리와 커널의 통신 문제를 고려해보자. 다대다 모델 또는 두 수준 모델다중 스레드 프로그램을 설계할 때 해결해야할 문제이다. 다대다 모델에서는 커널과 어떤 사용자 스레드끼리 짝을 짓고 알려면 표시할 정보가 필요하다.
이 때 사용되는 것이 LWP(Light Weight Process)이다.
LWP는 다수의 유저 스레드와 1개의 커널 스레드를 연결한다.
사용자가 입출력을 한다고 가정해보자. 입출력이 완료될 때 까지 사용중인 커널은 봉쇄된다. 이 때 커널은 스레드 라이브러리를 통해 새로운 LWP를 만들고 다른 유저 스레드에게 할당한다. 이 처럼 커널이 응용에게 특정 이벤트를 알려주는 것을 upcall이라고 한다.