운영체제 - chapter 4. 스레드와 병행성

2020. 12. 1. 18:28개인공부/운영체제 공룡책 10판

Chapter 4. 스레드와 병행성

  1. 개요
  2. 다중 코어 프로그래밍
  3. 다중 스레드 모델
  4. 스레드 라이브러리
  5. 암묵적 스레딩
  6. 스레드와 관련된 문제들
  7. 운영체제 사례
  8. 요약

 

4.1 개요 -p176

스레드는 CPU 이용의 기본 단위이다. 스레드는 스레드 ID, 프로그램 카운터 (PC), 레지스터 집합, 그리고 스택으로 구성된다. 스레드는 같은 프로세스에 속한 다른 스레드와 코드, 데이터 섹션, 그리고 열린 파일이나 신호와 같은 운영체제 자원들을 공유 한다.

 

4.1.1 동기 Motivation-p176

하나의 응용은 몇 개의 실행 흐름을 가진 독립적인 프로세스로 구현된다. 

 

-다중 스레드 응용 프로그램의 몇 가지 예

  • 이미지 모음에서 사진 축소판을 만드는 응용 프로그램은 별도의 스레드를 사용하여 개별 이미지에서 축소판을 생성할 수 있다.
  • 웹 브라우저는 하나의 스레드가 이미지 또는 텍스트를 표시하고 다른 스레드는 네트워크에서 데이터를 검색하도록 할 수 있다.
  • 워드 프로세서에는 그래픽을 표시하는 스레드, 사용자의 키 입력에 응답하는 또 다른 스레드 및 백그라운드에서 맞춤법 및 문법 검사를 검사를 수행하는 세 번째 스레드가 있을 수 있다.

싱글 스레드와 멀티 스레드 차이

 

 

웹 서버가 다중 스레드화 되면, 서버는 클라이언트의 요청을 listen 하는 별도의 스레드를 생성한다. 요청이 들어오면 다른 프로세스를 생성하는 것이 아니라, 요청을 서비스할 새로운 스레드를 생성하고 추가적인 요청을 listen 하기 위한 작업을 재개한다.

 

대부분의 운영체제 커널도 일반적으로 다중 스레드이다. 예를 들어 Linux 시스템에서 시스템을 부트하는 동안 여러 커널 스레드가 생성된다.

 

 

4.1.2 장점 -p178

1. 응답성

대화형 응용을 다중 스레드화하면 응용 프로그램의 일부분이 봉쇄되거나, 응용 프로그램이 긴 작업을 수행하더라도 프로그램의 수행이 계속되는 것을 허용함으로써, 사용자에 대한 응답성을 증가시킨다.

 

2. 자원 공유

프로세스는 공유 메모리와 메시지 전달 기법을 통해서만 자원을 공유할 수 있다. 스레드는 자동으로 그들이 속한 프로세스의 자원들과 메모리를 공유한다. 코드와 데이터 공유의 이점은 한 응용 프로그램이 같은 주소 공간 내에 여러 개의 다른 작업을 하는 스레드를 가질 수 있다는 점이다.

 

3. 경제성

스레드는 자신이 속한 프로세스의 자원들을 공유하기 때문에, 스레드를 생성하고 문맥 교환하는 것이 더욱더 경제적이다. 오버헤드의 차이를 경험적으로 측정하는 것은 어려울수 있지만, 문맥교환은 일반적으로 프로세스 사이보다 스레드 사이에서 더 빠르다.

 

4. 규모 적응성

다중 스레드의 이점은 다중 처리기 구조에서 더욱 증가 할 수 있다. 다중 처리기 구조에서는 각각의 스레드가 다른 처리기에서 병렬로 수행 될 수 있기 때문이다.

 

 

4.2 다중 코어 프로그래밍 -p178

각 코어는 운영체제에 별도의 CPU로 보인다. 이러한 시스템을 다중 코어라고 하며 다중 스레드 프로그래밍은 이러한 여러 컴퓨팅 코어를 효율적으로 사용하고 병행성을 향상시키는 기법을 제공한다.

 

병행 시스템:

모든 작업이 진행되게 하여 둘 이상의 작업을 지원한다.

 

병렬 시스템:

둘 이상의 작업을 동시에 수행할 수 있다. 따라서 병렬성 없이 병행성을 가질 수 있다.

 

 

 

4.2.1 프로그래밍 도전과제 -p179

응용 프로그래머는 기존 프로그램을 다중 스레드를 사용하도록 수정해야 하고 새로운 다중스레드 프로그램을 설계해야 하는 도전에 당면해 있다.

 

1. 태스크 인식 ( indentifying tasks )

응용을 분석하여 독립된 병행 가능 태스크로 나눌 수 있는 영역을 찾는 작업이 필요하다. 이상적으로는 태스크는 서로 독립적이고 따라서 개별 코어에서 병렬 실행될 수 있어야 한다.

 

2. 균형

병렬로 실행될 수 있는 태스크를 찾아내는 것도 중요하지만 찾아진 부분들이 전체 작업에 균등한 기여도를 가지도록 태스크로 나누는 것도 매우 중요하다.

 

3. 데이터 분리

응용이 독립된 태스크로 나누어지는 것처럼, 태스크가 접근하고 조작하는 데이터 또한 개별 코어에서 사용할 수 있도록 나누어져야 한다.

 

4. 데이터 종속성

태스크가 접근하는 데이터는 둘 이상의 태스크 사이에 종속성이 없는지 검토되어야 한다. 한 태스크가 다른 태스크로 부터 오는 데이터에 종속적인 경우에는 프로그래머가 데이터 종속성을 수용할 수 있도록 태스크의 수행을 잘 동기화 해야한다.

 

5. 시험 및 디버깅 

프로그램이 다중 코어에서 병렬로 실행될 때, 다양한 시랳ㅇ 경로가 존재할 수 있다.

 

 

4.2.2 병렬 실행의 유형 -p181

일반적으로 데이터 병렬 실행과 태스크 병렬 실행의 두 가지 유형이 존재한다. 데이터 병렬 실행은 동일한 데이터의 부분집합을 다수의 계산 코어에 부냅한 뒤 각 코어에서 동일한 연산을 실행하는 데 초점을 맞춘다.

 

태스크 병렬 실행은 데이터가 아니라 태스크(스레드)를 다수의 코어에 분배한다. 각 스레드는 고유의 연산을 실행한다.

 

기본적으로 데이터 병렬 처리에는 여러 코어에 데이터를 분배하는 것이 포함되고, 태스크 병렬 처리에는 여러 코어에 태스크를 분배하는 것이 포함된다. 그러나 데이터와 태스크 병렬 처리는 상호 배타적이지 않으며 실제로 응용 프로그램은 이 두가지 전략을 혼합하여 사용할 수 있다.

 

 

4.3 다중 스레드 모델 -p182

스레드를 위한 지원은 사용자 스레드(user threads)를 위해서는 사용자 수준에서, 또는 커널 스레드(kernel threads)를 위해서는 커널 수준에서 제공된다.

 

사용자 스레드와 커널 스레드는 어떤 연관 관계가 존재해야한다. 

 

연관 관계를 확립하는 세 가지 일반적인 방ㄷ법인 다대일, 일대일, 다대다 모델을 살펴본다.

 

4.3.1 다대일 모델 Many-to-One Model -p183

다대일(many to one) 모델은 많은 사용자 수준 스레드를 하나의 커널 스레드로 사상한다. 스레드 관리는 사용자 공간의 스레드 라이브러리에 의해 행해진다. 한 스레드가 봉쇄형 시스템을 콜을 할 경우, 전체 프로세스가 붕쇄된다.

 

다중 처리 코어의 이점을 살릴 수 없기 때문에 이 모델을 사용 중인 시스템은 거의 존재하지 않는다.

 

 

4.3.2 일대일 모델 One-to-One Model

일대일(one-to-one) 모델은 각 사용자 스레드를 각각 하나의 커널 스레드로 사상한다. 이 모델은 하나의 스레드가 붕쇄적 시스템 콜을 호출하더라도 다른 스레드가 실행될 수 있기 때문에 다대일 모델보다 더 많은 병렬성을 제공한다. 또한 이 모델은 다중 처리기에서 다중 스레드가 병렬로 수행되는 것을 허용한다. 

 

유일한 단점

사용자 스레드를 만들려면 해당 커널 스레드를 만들어야 하며 많은 수의 커널 스레드가 시스템 성능에 부담을 줄 수 있다.

 

 

 

4.3.3 다대다 모델 Many-toMany Model

다대다(many-to-many) 모델은 여러 개의 사용자 수준 스레드를 그보다 작은 수, 혹은 같은 수의 커널 스레드로 멀티 플렉스 한다. 커널 스레드의 수는 응용 프로그램이나 특정 기계에 따라 결정된다 ( 응용 프로그램은 4개의 코어 시스템보다 8개의 코어 시스템에서 더 ㅁ낳은 커널 스레드를 할당 받을 수 있다.)

 

개발자는 필요한 만큼 많은 사용자 수준 스레드를 생성할 수 있다. 또한, 스레드가 봉쇄형 시스템 콜을 발생시켰을 때, 커널이 다른 스레드의 수행을 스케줄 할 수 있다.

 

다대다 모델의 변형은 여전히 많은 사용자 스레드를 적거나 같은 수의 커널 스레드로 멀티플렉스 시키지만 또한 한 사용자 스레드가 하나의 커널 스레드에만 연관되는 것을 허용한다. 이 변형은 때로 두 수준 모델(two-level model)이라고 불리며 다대다 모델이 논의된 모델중 가장 융통성 있는 것으로 보이지만 실제로는 구현하기가 어렵다.

 

 

대부분의 시스템에서 처리 코어 수가 증가함에 따라 커널 스레드 수를 제한하는 것의 중요성이 줄어들었다. 결과적으로 대부분의 운영체제는 이제 일대일 모델을 사용한다.

 

 

 

Many to One, One to One, Many to Many

 

 

4.4 스레드 라이브러리 -p185

스레드 라이브러리(thread library)는 프로그래머에게 스레드를 생서하고 관리하기 위한 API를 제공한다.

라이브러리를 위한 모든 코드와 자료구조는 사용자 공간에 존재한다. 라이브러리의 함수를 호출하는 것은 시스템 콜이 아니라 사용자 공간의 지역 함수를 호출하게 된다는 것을 의미한다.

 

비동기 스레딩

부모가 자식 스레드를 생헝한 후 부모는 자신의 실행을 재개하여 부모와 자식 스레드가 서로 독립적으로 병행하게 실행된다. 스레드가 독립적이기 때문에 스레드 사이의 데이터 공유는 거의 없다. 비동기 스레딩은 다중 스레드 서버에서 사용되는 전략이고 반응형 사용자 인터페이스를 설계하는데에도 흔히 사용된다.

 

동기 스레딩 

부모 스레드가 하나 이상의 자식 스레드를 생성하고 자식 스레드 모두가 종료할 때까지 기다렸다가 자신의 실행을 재개하는 방식을 말한다. 부모가 생성한 스레드는 병행하게 실행되지만 부모는 자식들의 작업이 끝날 때까지 실행을 계속할 수 없다.

 

 

 

4.4.1 Pthread -p186

Pthreads는 POSIX가 스레드 생성과 동기화를 위한 제정한 표준 API다. 이것은 스레드의 동작에 관한 명세일 뿐이지 그것 자체를 구현한 것은 아니다.

 

4.4.2 Windows 스레드 -p188

Windows 스레드 라이브러리를 이용하여 스레드를 생성하는 기술은 많은 점에서 Pthreads 기법과 유사하다.

 

 

4.4.3 Java 스레드 -p190

스레드는 Java 프로그램 실행의 근본적인 모델이고, Java 언어와 API는 스레드의 생성과 관리를 지원하는 풍부한 특성을 제공한다. 모든 Java 프로그램은 적어도 하나의 단일 제어 스레드를 포함하고 있다.

 

단지 main() 함수로만 이루어진 단순한 Java 프로그램 조차 JVM 내의 하나의 단일 스레드로 수행된다. Java 스레드는 JVM을 제공 하는 어떤 시스템에서도 사용할 수 있다.

 

Java 프로그램에서 스레드를 명시적으로 생성하는 데에는 두 가지 기법이 있다.

1. Thread 클래스에서 파생된 새 클래스를 만들고 run() 메소드를 재정의 하는 것이다.

2.  Runnable 인터페이스를 구현하는 클래스를 정의하는것. 이 인터페이스는 public void run()의 서명을 가진 단일 추상 메소드를 정의한다. Runnable을 구현하는 클래스의 run()  메소드 코드는 별도의 스레드에서 실행된다.

 

예시)

class Task implements Runnable{
	
    public void run(){
    	System.out.println("I am a thread.");
    }
}

 

아래와 같이 Java 1.8부터 람다식으로 표현할 수 있다. ( Runnable을 구현하는 별도의 클래스를 정의하지 않아도 된다.!)

Runnable task = () -> {
	System.out.println("I am a thread.");
};

Thread worker = new Thread(task);
worker.start();

 

 

Java에서 스레드를 생성하려면

1.Thread 객체를 생성하고

2.Runnable 을 구현하는 클래스의 인스턴스를 전달한 다음

3.Thread 객체의 start() 메소드를 호출해야 한다.

Thread worker = new Thread (new Task());
worker.start();

 

 

새 Thread 객체에 대해 start() 메소드를 호출하면 두 가지 작업이 수행된다.

1. 메모리가 할당되고, JVM 내에 새로운 스레드가 초기화 된다.

2. run() 메소드를 호출하면 스레드가 JVM에 의해 수행될 자격을 갖게 한다. ( run() 메소드를 직접 호출하지 말것, 그 대신 start() 메소드를 호출하고 이 메소드가 사용자 대신 run() 메소드를 호출한다.)

 

 

Pthreads 및 Windows 라이브러리의 부모 스레드는 pthread_join() 및 Wait-forSingleObject()를 사용하여 각 스레드가 완료되기를 기다렸다가 계속 진행한다. Java의 join() 메소드는 유사한 기능을 제공한다. ( join()은 우리가 무시하기로 선택한 InterruptedException을 던질 수 있다.)

try{
	worker.join();
}
catch (InterruptedException ie){}

 

부모가 여러 스레드가 완료되기를 기다려야 하는 경우 Join() 메소드는 Pthread 보인 것과 비슷한 for 루프로 묶을 수 있다.

 

 

4.4.3.1 Java Executor 프레임 워크 -p192

 

Java는 개발자에게 스레드 생성 및 통신에 대한 제어 기능을 크게 향상시키는 몇 가지 새로운 병행 처리 기능을 도입하였다. 이 도구는 java.util.currunt 패키지에서 사용할 수 있다.

Executor 프레임워크는 생산자-소비자 모델을 기반으로 한다. Runnable 인터페이스를 구현하는 작업이 생성되고 이러한 작업을 실행하는 스레드가 이를 소비한다.

 

 

4.5 암묵적 스레딩 Implicit Threading -p194

 

병행 및 병렬 응용의 설계를 도와주는 한가지 방법은 스레딩의 생성과 관리 책임을 응용 개발자로부터 컴파일러와 라이브러리에게 넘겨주는 것이다. 

 

4.5.1 스레드 풀 -p195

스레드를 무한정 만들면 언젠가는 CPU시간, 메모리 공간 같은 시스템 자원이 고갈된다. 이러한 문제들을 해결해 줄 수 있는 방법의 하나가 스레드 풀(pool)이다. 

스레드 풀의 기본 아이디어는 프로세스를 시작할 때 아예 일정한 수의 스레드들을 미리 풀로 만들어두는 것이다. 이 스레드들은 평소에는 하는 일 없이 일감을 기다리게 된다.  스레드가 서비스를 완료하면 풀로 돌아가서 더 많은 작업을 기다린다. 풀에 제출된 작업을 비동기적으로 실행할 수 있는 경우 스레드 풀이 제대로 작동한다.

 

스레드 풀의 장점

1. 새 스레드를 만들어 주기보다 기존 스레드로 서비스 해주는 것이 종종 더 빠르다.

2. 스레드 풀은 임의 시각에 존재할 스레드 개수에 제한을 둔다. 이러한 제한은 많은 수의 스레드를 병렬 처리할 수 없는 시스템에 도움이 된다.

3. 태스크를 생성하는 방법을 태스크로부터 분리하면 태스크를 실행을 다르게 할 수 있다.

 

 

스레드 풀에 있는 스레드의 개수는 CPU수, 물리 메모리 용량, 동시 요청 클라이언트 최대 개수 등을 고려하여 정해질 수 있다.

 

 

4.5.1.1 Java 스레드 풀 Java Thread Pools-p196 

 

java.util.cuncurrent 패키지에는 여러 종류의 스레드 풀 구조에 대한 API가 포함되어 있다.

 

 

 

4.5.2 Fork Join -p197

스레드 생성 전략은 종종 fork-join 모델로 알려져 있다. 이 메소드를 사용하면 메인 부모 스레드가 하나 이상의 자식 스레드를 생성(fork) 한 다음 자식의 종료를 기다린 후 join하고 그 시점부터 자식의 결과를 확인하고 결합할 수 있다. ( 동기식 모델)

 

fork-join 모델은 라이브러리가 생성할 실제 스레드 수를 결정하는 동기 버전의 스레드 풀이다.

 

 

 

4.5.2.1 Java 에서의 Fork Join -p198

Java는 Quicksort 및 Mergesort와 같은 재귀분할 - 정복 알고리즘과 함께 사용되도록 설계된 버전 1.7 API에 fork join 라이브러리를 도입하였다. 이 라이브러리를 사용하여 분할-정복 알고리즘을 구현할 때 분할 단계 동안 별도의 작업이 fork 되고 원래 문제의 작은 부분집합이 할당된다.

 

 

 

 

 

 

 

 

4.5.3 OpenMP -p201

OpenMP는 C,C++, 또는 FORTRAN으로 작성된 API와 컴파일러 디렉티브의 집합이다. OpenMP는 공유 메모리 환경에서 병렬 프로그래밍을 할 수 있도록 도움을 준다. OpenMP는 병렬로 실행될 수 있는 블록을 찾아 병렬 영역 ( parallel regions )이라고 부른다.

 

OpenMP가 #pragma omp parallel 과 같은 컴파일러 디렉티브를 만나게 되면 시스템의 코어 개수만큼 스레드를 생성한다.

듀얼 코어는 2개, 쿼드 코어는 4개 이런 식으로 생성된다.

 

4.5.4 Grand Central Dispatch -p203

macOS 및 iOS 운영체제를 위해 Apple에서 개발한 기술이다. 개발자가 병렬로 실행될 코드 섹션(태스크)을 식별할 수 있도록 하는 런타임 라이브러리, API 및 언어 확장의 조합이다. OpenMP와 마찬가지로 GCD는 스레딩에 대한 대부분의 세부 사항을 관리한다.

 

GCD는 실행시간 수행을 위해 태스크를 디스패치 큐에 넣어서 스케줄 한다. GCD는 직렬(serial)과 병렬(concurrent) 두 가지 유형의 디스패치 큐를 유지한다. 직렬 큐에 넣어진 태스크는 FIFO 순서대로 제거된다. 태스크는 큐에서 제거되면 다른 태스크가 제거되기 전에 실행을 반드시 완료해야 한다.

 

각 프로세스에는 고유한 직렬 큐(메인 큐)가 있으며 개발자는 특정 프로세스에 로컬인 추가 직렬 큐를 만들 수 있다.

 

 

4.5.5 Intel 스레드 빌딩 블록 -p204

Intel TBB (treading building block)는 C++에서 병렬 응용 프로그램 설계를 지원하는 템플릿 라이브러리이다.

 

 

4.6 스레드와 관련된 문제들 -p206

 

4.6.1 Fork() 및 Exec() 시스템 콜 -p206

어떤 스레드가 exec() 시스템 콜을 부르면 exec()의 매개변수로 지정된 프로그램이 모든 스레드를 포함한 전체 프로세스를 대체 시킨다.

fork()를 부르자마자 다시 exec을 부른다면 모든 스레드를 다 복제해서 만들어주는 것은 불필요하다. 왜냐하면 exec에서 지정한 프로그램이곧 모든 것을 다시 대체할 것이기 때문이다. 이 경우에는 fork() 시스템 콜을 호출한 스레드만 복사해주는 것이 적절하다. 그러나 새 프로세스가 fork() 후 exec을 하지 않는다면 새 프로세스는 모든 스레드들을 복제해야 한다.

 

 

4.6.2 신호처리 -p206

신호는 UNIX에서 프로세스에 어떤 이벤트가 일어 났음을 알려주기 위해 사용된다. 신호는 알려줄 이벤트의 근원지나 이유에 따라 동기식 또는 비동기식으로 전달될 수 있다. 

 

동기식 & 비동기식 모두 아래와 같은 형태로 전달된다.

1. 신호는 특정 이벤트가 일어나야 생성된다.

2. 생성된 신호가 프로세스에 전달된다.

3. 신호가 전달되면 반드시 처리되어야 한다.

 

동기식 신호의 예로는 불법적인 메모리접근, 0으로 나누기 등이 있다.

 

모든 신호는 둘 중 하나의 처리기에 의해 처리된다.

1. 디폴트 신호 처리기 - 모든 신호마다 커널이 실행시킴

2. 사용자 정의 신호 처리기 - 디폴트 신호 처리기를 대체할수 있음

 

동기식 신호는 그 신호를 야기한 스레드에 전달되어야 하고 다른 스레드에 전달되면 안 된다.

비동기식 신호는 명확하지 않다. <Control + C> 같은 키를 쳐서 그 프로세스를 강제 종료하는 신호와 같은 어떤 비동기식 신호는 그 프로세스 내 모든 스레드에 전달되어야 한다.

 

4.6.3 스레드 취소 p208

스레드 취소는 스레드가 끝나기 전에 그것을 강제 종료시키는 작업을 일컫는다.

예를 들어 여러 스레드가 DB를 병렬로 검색하고 있다가 그 중 한 스레드가 결과를 찾았다면 나머지 스레드는 취소되어도 된다.

 

이처럼 취소되어야 할 스레드를 목적 스레드라고 부른다. 목적 스레드의 취소는 다음과 같은 두 가지 방식으로 발생할 수 있다.

1. 비동기식 취소(asynchoronous cancellation) : 한 스레드가 즉시 목적 스레드를 강제 종료시킨다.

2. 지연 취소 ( deferred cancellation) : 목적 스레드가 주기적으로 자신이 강제 종료되어야 할지를 점검한다. 이 경우 목적 스레드가 질서정연하게 강제 종료될 수 있는 기회가 만들어진다.

 

스레드 취소를 어렵게 만드는 것은 취소 스레드들에 할당된 자원 문제다. 또한 스레드가 다른 스레드와 공유하는 자료구조를 갱신하는 도중에 취소 요청이 와도 문제가 된다. 

 

스레드는 API를 사용하여 취소 상태 및 유형을 설정할 수 있다.

모드 상태 유형
Off 사용 불가능 -
지연 ( deferred ) 사용 가능 지연 ( deferred )
비동기식(asynchronous) 사용 가능 비동기식( asynchronous )

 

Pthreads는 스레드가 취소될 때 정리 핸들러 ( cleanup handler )라고 하는 함수가 호출되게 할 수 있다.

 

 

4.6.4 스레드-로컬 저장장치 -p210

한 프로세스에 속한 스레드들은 그 프로세스의 데이터를 모두 공유한다. 이와 같은 데이터 공유는 다중 스레드 프로그래밍의 큰 장점 중 하나이다. 그러나 상황에 따라서는 각 스레드가 자기만 액세스 할 수 있는 데이터를 가져야 할 필요도 있다. 그러한 데이터를 스레드-로컬 저장장치(thread0local storage, TLS)라고 부른다.

 

4.6.5 스케줄러 액티베이션 -p211

사용자 스레드 라이브러리와 커널 스레드 간의 통신 방법의 하나는 스케줄러 액티베이션이라고 알려진 방법이다. 커널은 응용에 가상 처리기(LWP)의 집합을 제공하고 응용은 사용자 스레드를 가용한 가상 처리기로 스케줄 한다. 

 

 

4.7 운영체제 사례 -p213

4.7.1 Windows 스레드 -p213

Windows 응용들은 프로세스 형태로 실행되며 이들 각 프로세스는 한 개 또는 그 이상의 스레드를 가질 수 있다.

 

스레드의 일반적인 구성요소

  • 각 스레드를 유일하게 지목하는 스레드ID
  • 처리기의 상태를 나타내는 레지스터 집합
  • 프로그램 카운터
  • 사용자 모드에서 실행될 때 필요한 사용자 스택, 커널모드에서 실행될 때 필요한 커널 스택
  • 실행 시간 라이브러리와 동적 링크 라이브러리(DLL) 등이 사용하는 개별 데이터 저장 영역

레지스터 집합,스택,개별 데이터 저장 영역들은 그 스레드의 문맥으로 불린다.

 

스레드의 주요 자료구조

  • ETHREAD - 실행 스레드 블록 ( executive thread block )
  • KTHREAD - 커널 스레드 블록 ( kernel thread block )
  • TEB - 스레드 환경 블록 ( thread environment block )

 

 

 

 

4.7.2 Linux 스레드 - p214

프로세스를 복제하는 기능을 가진 fork() 시스템 콜을 제공한다. Linux는 clone() 시스템 콜을 이용하여 스레드를 생성할 수 있는 기능도 제공한다. 그러나 Linux는 프로세스와 스레드를 구별하지 않는다. 사실 Linux는 프로그램 내의 제어 흐름을 나타내기 위하여 프로세스나 스레드보다 태스크라는 용어를 사용한다.

 

Linux 커널이 태스크를 표현하는 방식 때문에 다양한 공유 수준이 가능하다. 시스템의 태스크마다 고유한 커널 자료구조가 존재한다. 이 자료구조는 태스크의 데이터를 저장하는 것이 아니라 데이터가 저장된 다른 자료구조를 가리키는 포인터를 포함한다.

 

4.8 요약 -p215

1. 스레드는 CPU 사용의 기본 단위를 나타내며 동일한 프로세스에 속하는 스레드는 코드 및 데이터를 포함하여 많은 프로세스 자원을 공유한다.

 

2. 다중 스레드 응용 프로그램에는 (1) 응답성, (2) 자원 공유, (3) 경제성 및 (4) 확장성 이라는 4자기 주요 이점이 있다.

 

3. 여러 스레드가 진행 중인 경우 병행성이 존재하는 반면에 여러 스레드가 동시에 진행 중인 경우 병렬성이 존재한다. 단일 CPU가 있는 시스템에서는 오로지 병행성만 가능하고, 병렬성은 여러 CPU를 제공하는 다중 코어 시스템이 필요하다.

 

4. 다중 스레드 응용 프로그램을 설계하는 데 몇 가지 도전과제가 있다. 작업 분할 및 균형 조정, 서로 다른 스레드 간에 데이터 분할 및 데이터 종속성 식별이 포함된다. 마지막으로 다중 스레드 프로그램은 테스트 및 디버깅에 특히 어려움이 있다.

 

5. 데이터 병렬 처리는 동일한 데이터의 부분 집합을 다른 컴퓨팅 코어에 분산시키고 각 코어에서 동일한 연산을 수행한다. 작업 병렬 처리는 여러 코어에 데이터가 아니라 작업을 분산시킨다. 각 작업은 고유한 연산을 실행한다.

 

6. 사용자 응용 프로그램은 사용자 수준 스레드를 생성하며, 이 스레드는 궁극적으로 CPU에서 실행되도록 커널 스레드에 매핑 되어야 한다. 다대일 모델은 많은 사용자 수준 스레드를 하나의 커널 스레드에 매핑한다. 다른 접근 법으로는 일대일 및 다대다 모델이 있다.

 

7. 스레드 라이브러리는 스레드를 만들고 관리하기 위한 API를 제공한다. 세 가지 일반적인 스레드 라이브러리에는 Windows, Pthreads 및 Java 스레딩이 있다. Windows는 Windows 시스템 전용이며 Pthreads는 UNIX, Linux 및 macOS와 같은 POSIX 호환 시스템에서 사용할 수 있다. Java 스레드는 Java 가상 머신을 지원하는 모든 시스템에서 실행된다.

 

8. 암묵적 스레딩에는 스레드가 아니라 작업을 식별하고 언어 또는 API 프레임워크가 스레드를 만들고 관리할 수 있게 한다 스레드 풀, fork join 프레임워크 및 Grands Central Dispatch를 포함하여 암묵적 스레딩에 대한 몇 가지 접근 방식이 있다. 암묵적 스레딩은 프로그래머가 병행 및 병렬 응용 프로그램을 개발할 때 점점 더 보편적인 기술이 되고 있다.

 

9. 스레드는 비동기 또는 지연 취소를 사용하여 종료될 수 있다. 비동기 취소는 스레드가 업데이트를 수행하는 중이라도 스레드를 즉시 중지한다. 지연 취소는 스레드에 종료해야 한다고 통지하지만 스레드는 질서 정연하게 종료된다. 대부분의 경우 비동기 종료보다 지연 취소가 선호된다.

 

10. 다른 많은 운영체제와 달리 Linux는 프로세스와 스레드를 구분하지 않는다. 대신, 각각을 태스크라고 한다. Linux clone() 시스템 콜을 사용하여 프로세스와 더 비슷하거나 스레드와 더 비슷한 태스크를 만들 수 있다.