쓰레드 (thread)
- 프로세스 내에서 실행되는 흐름의 단위
- OS 스케줄러에 의해 관리될 수 있는 가장 작은 단위의 프로그램 조각
- 주 프로그램과는 독립적으로 실행되는 함수
- 프로세스 내의 다른 쓰레드와 주소공간과 전역변수 등의 데이터는 공유
- 레지스터, 스택, 시그널 마스크 등은 쓰레드 별로 별도 보유
쓰레드 등장 배경
-
소프트웨어 설계 요구
- 병렬처리 작업이 자연스러운 응용 시스템 개발 필요
-
하드웨어 병렬처리 지원
- 멀티코어, 멀티프로세서 컴퓨터의 보편화
- 병렬처리 환경 조성
-
효율적 협업 작업 필요
- 프로세스간 통신(IPC)보다 공유 주소공간을 통한 데이터 교환의 효율성
사용자 수준 쓰레드와 커널 수준 쓰레드
사용자 수준 쓰레드
- 사용자 공간 쓰레드 라이브러리에 의한 쓰레드 관리
커널 수준 쓰레드
사용자 수준 쓰레드
- 사용자 수준에서 쓰레드 구현
- 실행시간 시스템(run-time system)에 의해 쓰레드 관리
- 모든 쓰레드 관련 연산이 사용자 수준에서 수행
- 새로운 쓰레드 생성 (create)
- 쓰레드간 전환 (switch)
- 쓰레드간 동기화 (synchronize)
- 쓰레드 스케줄러를 라이브러리로 제공
- 커널은 사용자 수준 쓰레드의 존재를 알지 못함
사용자 수준 쓰레드의 다중화
- 사용자 수준 쓰레드에서는 커널 수준 쓰레드를 가상의 프로세서로 간주
- 사용자 수준 쓰레드들이 번갈아 가면서 커널 수준 쓰레드 사용
ex) Solaris Green Thread, GNU Portable Threads
사용자 수준 쓰레드
- N:1 관계
- FreeBSD 쓰레드 라이브러리 libc_r
- 커널 스택
- 외부 인터럽트, 예외상황, 시스템 호출을 통해 커널로 진입할 때, 진행중이던 프로세스의 문맥정보를 저장하고, 해당 핸들러 등이 동작하면서 사용하는 프로세스별로 커널영역에 할당된 공간
- 80x86 CPU의 커널 스택 크기: 8KB
커널 수준 쓰레드
- 각 사용자 수준 쓰레드별로 별도 커널 실행문맥 생성
- 커널에 의해 관리
- 각 쓰레드는 커널 자원 사용
- 생성 가능한 쓰레드 개수의 제한 발생
- 멀티프로세서의 성능 활용 가능
- 동시 실행 가능 쓰레드 지원
ex) Windows NT/XP/2000, Linux, Solaris 9 이후
커널 수준 쓰레드
- 1:1 관계
- 쓰레드간 문맥교환 시간 부담
- 시스템 호출을 통한 쓰레드 연산 부담: 커널은 사용자에 대해 신뢰하지 않기 때문에 시스템 호출에 대해 여러가지 항목 검사 수행
- Linux의 Thread (프로세스 기반 쓰레딩)
- 사용자 수준 쓰레드를 프로세스와 동일하게 간주
- 하나의 사용자 수준 쓰레드는 주소공간을 공유하는 프로세스처럼 관리
- 쓰레드와 프로세스를 태스크(task)로 관리
사용자/커널 수준 쓰레드 혼합
- 사용자 수준 쓰레드와 커널 수준 쓰레드의 다-대-다 대응관계
- ex) Windows XP's fiber library, AIX Pthreads, Solaris LWP
- M:N 관계
- Solaris의 LWP
- 쓰레드가 이미 만들어 놓은 프로세스 풀(LWP 모임)을 이용하여 실행
- 사용자 수준 쓰레드 스케줄러에 의해 쓰레드 스케줄링 수행
- 사용자 수준 쓰레드가 커널 수준 쓰레드(LWP)에 매핑되면서 프로세서에서 실행
쓰레드 생명주기
쓰레드 관련 작업
- 생성 (create)
- 종료 (exit, terminate)
- exit를 요청한 쓰레드를 종료
- 일시정지 (suspend)
- 재시작 (resume)
- 수면 (sleep)
- 깨우기 (wake up)
- 취소 (cancel)
- 특정 쓰레드가 완료되기 전에 종료시키기
- 조인 (join)
- 특정 쓰레드가 종료할 때까지 대기
쓰레드의 시그널 처리
시그널 처리
- 프로세스에 전달된 시그널은 해당 프로세스의 모든 쓰레드에 전달
- 각 쓰레드는 받고 싶은 시그널만 수신하도록 마스킹(masking) 가능
- 시그널은 프로세스 내의 특정 쓰레드, 전체 또는 일부에 전달 가능
- 동일 프로세스에 등록된 시그널의 처리기는 쓰레드들이 공유
- 실행 상태가 아닌 쓰레드에 전달되는 시그널은 대기 시그널 대기열에 저장
- 실행 상태가 되면 대기열의 시그널 처리
- 시그널에 의해서 특정 쓰레드가 종료를 하게 되면, 해당 쓰레드를 포함한 프로세스가 전체 쓰레드도 종료
POSIX Threads
Pthreads
- 쓰레드 생성 및 동기화를 위한 POSIX 표준 API
- API는 쓰레드 라이브러리의 동작에 대해서만 명세
- UNIX 계열 OS(Solaris, Linux, Mac OS X 등)에서 대부분 지원
- Pthreads 함수의 예
- Pthread_create: 새로운 쓰레드 생성
- Pthread_exit: 호출한 쓰레드 종료
- Pthread_join: 지정한 쓰레드가 종료할 때까지 대기
- Pthread_yield: 프로세서를 다른 쓰레드가 사용하도록 양보
- Pthread_attr_init: 쓰레드 속성 구조체 생성 및 초기화
- Pthread_attr_destroy: 쓰레드 속성 구조체 제거
Linux 쓰레드
- 프로세스와 쓰레드를 모두 task라고 함
- 동일한 자료구조(PCB) task_struct 사용 표현
- 자식 태스크 생성을 위해 시스템 호출 fork() 사용
- 쓰레드 생성을 위해 시스템 호출 clone() 사용
- 자원 공유 관련 시스템 호출 플래그
플래그
- CLONE_FS: 파일시스템 정보 공유
- CLONE_VM: 메모리 공간 공유
- CLONE_SIGHAND: 시그널 처리기 공유
- CLONE_FILES: 열린 파일 공유
- CLONE_PID: 부모 프로세스와 동일한 프로세스 식별번호 사용
- CLONE_NEWUTS: 새로운 UTS 네임스페이스 생성
- SIGCHLD: 종료시 부모 프로세스에 SIGCHLD 시그널 전달
Java 쓰레드
Java 쓰레드 생성 방법
- 클래스 Thread를 상속한 클래스의 run() 정의
- 인터페이스 Runnable를 구현한 클래스의 run() 정의