다중 쓰레드 프로그램 설계 시 고려해야 할 몇 가지 점을 알아보자.
fork()와 exec() 시스템 콜
만약 한 프로그램의 쓰레드가 fork()를 호출한다면
- 새 프로세스는 모든 쓰레드를 복제해야 하는가?
- 아님 한 개의 쓰레드만을 가져야 하는 프로세스여야 하는가?
몇몇 유닉스는 이 두 모드를 동시에 지원한다. 이를 선택하는 것은 결국 App 설계자의 몫.
exec()의 경우 모든 쓰레드를 포함한 전체 프로세스를 대체한다.
신호처리
신호의 정의와 처리
💡 신호 = 프로세스에 어떠한 이벤트가 일어났음을 알려주기 위해 사용됨.
모든 신호는 다음과 같은 형태로 전달된다.
- 신호는 특정 이벤트가 일어나야 생성된다.
- 생성된 신호가 프로세스에 전달된다.
- 신호가 전달되면 반드시 처리해야 한다.
동기식 신호 : 실행 중인 프로세스 내부에서 발생한 신호
- 예시 : 불법적 메모리 접근, 0으로 나누기
- 신호를 발생시킨 연산을 수행한 동일한 프로세스에만 전달
비동기식 신호: 실행 중인 프로세스 외부에서 발생한 신호
- 예시 : ctrl + c, 타이머 만료
모든 신호는 둘 중 하나에 의해 처리된다.
- 디폴트 신호 처리기
- 사용자 정의 신호 처리기
신호처리와 쓰레드
단일 쓰레드 : 신호는 항상 프로세스에 전달
다중 쓰레드 : 여러가지 경로가 존재.
- 신호가 적용될 쓰레드에 전달
- 모든 쓰레드에 전달
- 몇몇 쓰레드에 선택적 전달
- 특정 쓰레드가 모든 신호를 받는다.
비동기식 신호의 경우에는 특히 이러한 선택지가 원할하지 않다.
-
kill() 의 경우 특정 신호가 전달될 프로세스를 지정
-
대부분의 다중 쓰레드 지원 유닉스는 받아드릴 신호와
봉쇄할 신호를 지정할 선택권을 부여한다.
쓰레드 취소
쓰레드 강제종료를 의미한다. 이때의 쓰레드를 목적 쓰레드라고 한다.
목적 쓰레드의 취소는 2가지 방식으로 발생시킬 수 있다.
- 비동기식 취소 : 한 쓰레드가 즉시 목적 쓰레드를 강제 종료
- 지연 취소 : 목적 쓰레드가 주기적으로 자신이 종료대상인지 점검.
쓰레드 취소를 어렵게 하는 것은 취소 쓰레드에 할당된 자원 문제.
또 쓰레드가 타 쓰레드와 자원을 공유하는 상황에서 취소 요청이 와도 문제.
- 따라서 비동기식 취소는 필요한 자원을 다 회수하지 못 할 수도 있다.
- 그래서 기본적인 유형은 지원 취소이다.
쓰레드-로컬 저장장치
각각의 쓰레드만 접근할 수 있는 데이터가 필요하기도 하다.
이를 저장하는 곳은 쓰레드-로컬 저장장치 (TLS)라고 한다.
중요한 점은 TLS와 지역변수가 다르다는 것!
- 지역변수 : 하나의 함수에 국한.
- TLS : 전체 함수 호출에 걸쳐 보인다.
정적 데이터(static)과 좀 더 유사.
스케쥴러 액티베이션
쓰레드 라이브러리와 커널의 통신 문제도 고려해야 한다.
- 특히 다대다 또는 2수준 모델에서 더 중요하다.
- 얼마나 많은 커널 쓰레드가 필요한지 파악 후 조절
이 경우, 사용자 쓰레드와 커널 쓰레드 사이에 중간 자료구조를 둔다.
-
이를 경량 프로세스(LWP) 라고 한다.
-
프로그램의 효율적 실행을 위해 LWP의 갯수를 조정해야 할 수도 있다.
-
사용자 스레드 라이브러리에게 있어, LWP은 응용이 사용자 스레드를 스케줄할 수 있는 가상 처리기처럼 보인다.
커널은 관여하지 않는 것처럼 보인다.
-
LWP는 하나의 커널 스레드에 부속되어 있으며, 사용자 스레드와도 연결되어 있다.
-
물리 처리기에서 스케줄 하는 대상은 커널 스레드이다.
-
커널 스레드가 입출력같은 것을 동기식으로 기다리면 LWP가 기다리고, 이에 연결된 사용자 스레드도 기다린다.
사용자 스레드 라이브러리와 커널 스레드 간의 통신 방법 중 하나는 스케줄러 액티베이션이다.
- 커널은 응용 프로그램에게 가상 처리기 집합(LWP)을 제공한다.
- 응용 프로그램을 이를 통해 사용자 스레드를 스케줄 한다.
커널은 upcall 이라 불리는 프로시저를 통하여 응용 프로그램에게 사건을 알린다.
- 사건은 응용 프로그램의 스레드가 봉쇄(동기)하려고 할 때 발생한다.
- upcall은 가상 처리기에서 수행되는, 스레드 라이브러리의 upcall 처리기에 의해 처리된다.
upcall 처리는 다음과 같이 수행된다.
- 커널이 스레드가 봉쇄하려고 하는 것과 스레드의 식별자를 알려주는 upcall을 한다.
- 커널이 새로운 가상 처리기를 응용 프로그램에게 할당한다.
- 응용 프로그램이 새로운 가상 처리기에서 upcall 처리기를 수행한다.
- upcall 처리기는 봉쇄 스레드의 상태를 저장하고 원래 가상 처리기를 반환한다.
- upcall 처리기는 새로운 가상 처리기에서 응용 프로그램의 실행 가능한 스레드를 스케줄 한다.
- 커널이 봉쇄가 풀리는 사건을 감지하고 upcall을 스레드 라이브러리에게 한다.