개요
✅ 스레드는 CPU 이용의 기본단위.
✅ 스레드는 스레드 ID, 프로그램 카운터(PC), 레지스터 집합, 그리고 스택으로 구성
✅ 스래드는 같은 프로세스에 속한 다른 스레드와 코드, 데이터 섹션, 그리고 열린 파일이나 신호와 같은 운영체제 자원들을 공유
✅ 프로세스가 다수의 제어 스레드를 가진다면 프로세스는 동시에 하나 이상의 작업을 수행할 수 있다.
동기 (Motivation)
✅ 현대의 컴퓨터와 모바일 기기에서 작동하는 거의 모든 소프트웨어 응용들은 다중 스레드 이용
✅ 다중 스레드 응용 프로그램의 몇가지 예
-> 이미지 모음에서 사진 축소판을 만드는 응용 프로그램은 별도의 스레드를 사용해 개별 이미지에서 축소판을 생성 할 수 있다.
-> 웹 브라우저는 하나의 스레드가 이미지 또는 텍스트를 표시하고 다른 스레드는 네트워크에서 데이터를 검색하도록 할 수 있다
✅ 응용은 다중 코어 시스템에서 처리 능력 향상시키도록 설계될 수 있다.
✅ 이러한 응용은 다중 계산 코어를 사용하여 다중의 CPU- 집중작업을 병렬로 처리할 수 있다.
✅ 하나의 응용 프로그램이 여러 개의 비슷한 작업을 수행할 필요가 있는 상황 들 존재
-> 예를들어, 웹 서버는 클라이언트로부터 웹 페이지나 이미지, 소리 등에 대한 요청을 받는다. 하나의 분주한 웹서버는 여러 개의 클라이언트들이 병행하게 접근할 수 있다.
멀티 스레드
✅ 멀티 스레드는 CPU의 최대 활용을 위해 프로그램 둘 이상을 동시에 실행 시키는 기술
✅ 이러한 작업은 문맥 교환 (context switching)을 통해서 이루어진다
✅ 하나의 스레드에서 다른 특정 스레드로 문맥 교환이 일어나고 스위칭이 일어나면서 부분적으로 조금씩 서로의 업무를 수행하가며 각자의 작업을 완료해 나가는 것이다.
✅ 즉 문맥교환을 엄청난 속도로 이뤄내면서 유저의 시선에는 동시에 프로세스들이 수행되는것 처럼 보이는 것이다.
싱글 스레드
✅ 하나의 프로세스에서 오직 하나의 스레드로만 업무 수행 그러므로 하나의 레지스터와 스택으로 표현이 가능
✅ 코드, 데이터, 힙 영역을 함께 공유함
✅ 스택 영역만 스레드 별로 보유하게됨.
✅ 파일영역, 레지스터, 스택 모두 가지고 있음.
✅ 코드의 독립적인 시퀀스가 존재하므로 각 스레드의 path 마다 상이한 코드정보를 갖게됨
✅ 각각의 다른 함수로 만들어진 스레드들은 전부 다른 메모리 스택을 가지고 있음.
✅ 각각의 스레드들은 서로 가드를 그어서 구분지음
✅ 각 스레드 안에서도 함수 안에 다른 함수가 호출 될 수 있기에 가드 생성
멀티 프로세스
✅ 멀티 프로세스는 두 개 이상의 다수의 프로세서(CPU)가 협렵적으로 하나 이상의 작업을 동시에 처리하는 것
-> 프로세스 생성 작업은 매우 많은 시간을 소비하고 많은 자원을 필요로함
-> 하지만 새 프로세스가 기존의 프로세스와 하는일이 비슷하다면 굳이 이러한 오버헤드를 감수해야 할 필요가 없음.
-> 대부분은 그렇게 하는 것 보다 프로세스 안에 여러 스레드를 만들어 나가는 것이 더 효율적.
멀티 스레드
✅ 웹 서버가 다중 스레드화 되면 서버는 클라이언트의 요청을 listen 하는 별도의 스레드 생성
✅ 요청이 들어오면 다른 프로세스를 생성하는 것이 아니라 요청을 서비스할 새로운 스레드를 생성하고 추가적인 요청을 listen 하기 위한 작업 재개
✅ 단일 컴퓨팅 칩에 여러 컴퓨팅 코어 배치.
✅ 각 코어는 운영체제에 별도의 CPU로 보인다. (다중 코어)
✅ 다중 스레드 프로그래밍은 이러한 여러 컴퓨팅 코어를 보다 효율적으로 사용하고 병행성을 향상 시키는 기법을 제공
✅ 단일 코어 프로그래밍에서는 여러개의 스레드가 있는 응용 프로그램을 처리할 때 처리 코어가 하나밖에 없으므로 단지 하나의 스레드만 실행 가능하다 그렇기 때문에 병행성은 시간이 지남에 따라 스레드 실행이 인터리브됨을 의미한다.
✅ 그러나 여러 코어가 있는 시스템에서의 병행성은 시스템이 각 코어에 별도의 스레드를 할당 할 수 있기 떄문에 일부 스레드가 병렬로 실행될 수 있다.
데이터 병렬 실행
✅ 동일한 데이터의 부분집합을 다수의 계산 코어에 분배한 뒤 각 코어에서 동일한 연산을 실행하는데 초첨을 맞춤
✅ 0 ~ N 까지의 크기를 가지고 있는 배열을 더할 때 절반은 스레드 A, 절반은 스레드 B에서 더해서 둘이 더하게 되는 방식
테스크 병렬 실행
✅ 데이터가 아니라 테스크(스레드)를 다수의 코어에 분배
✅ 각 스레드는 고유의 연산 실행
✅ 다른 스레드들이 동일한 데이터에 대해 연산을 실행 할 수 있고 혹은 서로 다른 데이터에 연산을 실행할 수 있음
✅ 위의 상황과 대조적으로 배열에 대해 각자 고유한 통계 연산을 수행하는 2개의 스레드가 필요할 수 있음 이 스레드들은 개별 코어에서 병렬로 실행되지만 각각 고유한 연산 수행
✅ 기본적으로 데이터 병렬처리에는 여러 코어에 데이터를 분배하는 것이 포함되고, 테스크 병렬 처리에서는 여러 코어에 테스크를 분배하는 것이 포함된다.
✅ 하지만 데이터/테스크 병렬처리는 상호 배타적이지 않으며 혼용돼서 사용
유저 스레드
✅ 사용자 스레드는 커널 위에서 지원되며 커널의 지원없이 관리된다.
✅ 라이브러리 형태로 구현
✅ 프로세스 무거워짐
✅ 커널은 동작하는 스레드가 끝날 때 까지 기다려야함
✅ 운영체제 한테는 안보임
✅ 크기가 작음
커널 스레드
✅ 운영체제에 의해 직접 지원되고 관리됨
✅ 윈도우, 리눅스, 맥OS를 포함한 거의 모든 현대 운영체제들은 커널 스레드 지원
✅ 스레드 테이블을 가지고 있어 커널에서 스레드를 관리함
✅ 비용이 비쌈
✅ 멀티 프로세스 보다는 저렴
다대일 모델 (Many - to - One Model)
✅ 많은 사용자 수준 스레드를 하나의 커널 스레드로 사상
✅ 스레드 관리는 사용자 공간의 스레드 라이브러리에 의해 행해짐 따라서 효율이지만 한 스레드가 봉쇄형 시스템 콜을 할 경우 전체 프로세스 봉쇄됨.
✅ 또한 한 번에 하나의 스레드만이 커널에 접근할 수 있기 때문에 다중 스레드가 다중 코어 시스템에서 병렬로 시행될 수 없음.
일대일 모델 (One - to - One Model)
✅ 일대일 모델은 각 사용자 스레드를 각각 하나의 커널 스레드가 사상
✅ 이 모델은 하나의 스레드가 봉쇄적 시스템 콜을 수행하더라도 다른 스레드가 실행될 수 있으므로 다대일 모델보다 더 많은 병렬성 제공 또한 다중 처리기에서 다중 스레드가 병렬로 수행되는 것을 허용
✅ 하지만 단점은 사용자 스레드를 만들려면 해당 커널 스레드를 만들어야 하며 많은 수의 커널 스레드가 시스템 성능에 부담을 줄 수 있음
다대다 모델 ( Many to Many Model)
✅ 다대다 모델은 여러 개의 사용자 수준 스레드를 그보다 작은 수 혹은 같은 수의 커널 스레드로 멀티플렉스 한다
✅ 커널 스레드의 수는 응용 프로그램의이나 특정 기계에 따라 결정됨
✅ 융통성이 있어보이지만 실제로 구현 어려움
✅ 또한 대부분의 시스템에서 처리 코어 수가 증가함에 따라 커널 스레드 수를 제한하는 것의 중요성이 줄어듬
✅ 결과적으로 대부분의 운영체제는 일대일 모델 사용
fork( ) 및 exec( ) 시스템 콜
✅ 만일 한 프로그램의 스레드가 fork()를 호출하면 새로운 프로세스는 모든 스레드를 복제해야 하는가 아니면 한 개의 스레드만 가지는 프로세스여야 할까? UNIX기종은 이 두 가지 버전 fork()를 모두 제공한다.
✅ exec()의 경우 시스템 콜을 하면 exec()의 매개변수로 저장된 프로그램이 모든 스레드를 포함한 전체 프로세스를 대체시킨다.
✅ 응용 프로그램에 따라 어떤 fork()를 선택할 지 정해진다.
✅ fork()를 한 후 exec() 시스템 콜을 호출한다면 모든 스레드를 다 복제해서 만들어주는 것은 불필요하다.
✅ 이런 경우에는 fork() 시스템 콜을 호출한 스레드만 복사해주는 것이 적절한다. 그러나 새 프로세스가 fork()후 exec를 하지 않는다면 새 프로세스는 모든 스레드들을 복제 해야한다.
✅ 참고로 멀티 스레드를 포함하는 프로세스에 대해서는 절대 fork() 요청을 하지 않음.
✅ 포크 후 멀티 스레딩을 하는것이 대체적인 규약.
스레드 취소(Thread cancelllation)
✅ 스레드가 데이터베이스를 병렬로 검색하고 있다가 그 중 한 스레드가 결과를 찾은 경우.
✅ 병렬로 실행되던 나머지 스레드는 취소되어도 된다. 이처럼 스레드가 끝나기 전에 그것을 강제 종료시키는 작업을 스레드 취소라고 한다.
신호 처리 (Signal handling)
✅ 모든 신호는 둘 중 하나의 처리기에 의해 처리된다.
1 ) 디폴트 신호 처리기 - 커널이 실행
2 ) 사용자 정의 신호 처리기
✅ 단일 스레드 프로그램에서는 신호 처리는 매우 간단하다.
✅ 신호는 항상 프로세스에 전달된다. 하지만 다중 스레드 프로그램에서의 신호 처리는 복잡하다. 어느 스레드에 신호를 전달해야 하는가?
✅ 신호를 전달하는 방법은 신호의 유형에 따라 다르다.
✅ 예를 들면 동기식 신호는 그 신호를 야기한 스레드에 전달되어야 한다. 비동기식 신호의 경우는 명확하지 않다. 그 프로세스를 강제 종료하는 신호와 같은 어떤 비동기식 신호는 그 프로세스 내 모든 스레드에 전달되어야 한다.