본문 바로가기
공부/운영체제

운영체제4 Threads

by 맑은청이 2020. 6. 17.
728x90
반응형

이번 단원에서는 아래 목표를 가지고 공부를 할 것 입니다.

 

1. Thread의 개념 이해

2. APIs (Pthreads, Windows ,and Java thread libraries)

3. Thread의 기본적 특성

4. multithread programming

5. Window, Linux 에서는 thread 가 어떻게 제공되는지 

 

그럼 시작하겠습니다.

 

 


현재 컴퓨터에서는 거의 다 multithread 개념을 사용합니다. 

만약 한 프로세스가 다음과 같은 기능들을 수행할 수 있다고 가정해봅시다.

- 업데이트

- 데이터 가져오기

- 오류 체크하기

- 네트워크 응답하기

 

여기서 네트워크 응답하기 속도가 굉장히 느리다고 가정했을때 단일 스레드라면 이걸 실행했을때 컴퓨터가 멈춰버리게 됩니다. 요새 컴퓨터가 뭐 다운로드 받는다고 컴퓨터가 멈춰버리는 거 보신 적 있으신가요? 이는 다 멀티스레드를 사용하기 때문에 다운로드를 받는 중에도 업데이트를 하면서 데이터를 가져오고 오류체크가 가능한 겁니다. 그리고 Process 하나 생성하는 건 무거운 작업이지만 thread를 하나 생성하는 건 가벼운 작업입니다. 

 

커널은 일반적으로 multithread기반입니다.

서버가 스레드를 처리하는 과정

1. client 가 server 에 요청

2. 서버는 스레드 하나를 만들어서 ' 너가 이 요청 수행해' 라고 처리부분을 스레드에게 넘깁니다. 

3. client 가 또다른 요청을 하면 서버는 새로운 스레드를 만들어서 그 처리부분을 스레드에게 넘깁니다. 

4. 서버는 이처럼 client 의 추가 요청을 listening 합니다. 

 

 

-thread 의 Benefits

1. Responsiveness - 프로세스는 동작이 많으면 컴퓨터가 느려진다는 느낌을 받지만 스레드는 그렇지 않습니다.

2. Resource Sharing - 자원 공유가 조금 더 쉽습니다. 

3. Economy

4. Scalablity(확장성)

 

 

 

다음은 ConcurrencyParallenlism 에 대해 알아보겠습니다.

 

-Concurrency : 빠르게 시분할하면서 병렬로 실행되고 있는 거처럼 보이는거(single-core)

 

-Parallenlism : 정말 병렬적으로 태스크가 실행이 되고 있는거(multi-core)

 

이처럼 요새 컴퓨터는 거의 Multicore 또는 Multiprocessor 로 진행이 됩니다. 여기서 오는 이슈들이 또 있습니다. 

 

1. Dividing activities : 일을 병렬로 쪼갤 수 있느냐 만약 순차적으로 task 가 진행이 된다면 task 분할이 굉장히 어려워집니다.( 1의 결과로 2를 시행 , 2의 결과로 3을 시행, 1 ,2 전에 3을 시행할 수가 없음 -> task 분할 어려움) 

2. Balance : 두개의 테스크가 있습니다. 하나는 엄청 빠르고 하나는 엄청 느립니다. 사실 느린 하나의 태스크를 분할 했어야하는데 그러지 못하면 과정이 굉장히 느려집니다. 이렇게 균형을 맞추는 게 중요한 이슈가 됩니다. 

3. Data splitting 

4. Data dependency

5. Testing and debugging : 어려워집니다. 

 

 

▶Single and Multithreaded Processes

Single-threaded process각자 code,data,files 등의 자원 구조를 씁니다. 

Multithreaded process는 이 자원들을 공유(shared)합니다. 

 

 

 

Amdahl's Law 

컴퓨터 구조 시간에도 나왔지만 속도는 결국 S, 즉 병렬화가 얼마나 되었는지에 의해 결정이 됩니다. 여기서 N은 '코어의 수'입니다. 좀 더 자세히 알고 싶은 분은 다음 포스팅을 참고해주세요.

 

https://com24everyday.tistory.com/70?category=1125097

 

컴퓨터구조2 Process

안녕하세요. 옆집컴공생입니다. 오늘은 프로세스 효율에 영향을 미치는 부분과 고성능 프로세스 설비에 어떤게 필요한지에 대해 알아볼 것 입니다. 요즘 컴퓨터의 비용은 싸지고 수행 능력과 ��

com24everyday.tistory.com

 

Thread의 구조

Thread는 크게 사용자 스레드(User threads)냐 커널 스레드(Kernel threads)냐로 나눌 수 있습니다.

 

1. User threads : User 레벨의 애플리케이션, 그리고 그 애플리케이션의 라이브러리로 관리가 됩니다.

 - POSIX Pthreads

 - Windows threads

 - Java threads

2. Kernel threads : OS kernel에 있어서 스레드가 어떤 식으로 제공이되고 그 기능들

 - Windows

 - Solaris

 - Linux

 - Tru64 UNIX

 - Mac OS X

 

 

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

-Many-to-One

-One-to-One

-Many-to-Many

 

 

Many-to-One

 

User입장에서 보면 여러개의 스레드지만 실제 커널에서 제공하는 스레드는 하나입니다. 

하나의 스레드가 blocking 이 되면 나머지 스레드도 다 blocking이 됩니다. 

요즘은 이 모델을 쓰지 않습니다. 

(Solaris Green Threads, GNU Portable Threads)

 

 

 

One-to-One

하나의 스레드당 커널 스레드 하나씩 매칭

너무 많이 생성하면 성능이 떨어집니다. (스케쥴링 문제, 메모리문제)

(Windows, Linux, Solaris 9 and later)

 

 

Many-to-Many

 

얼핏 보면 좋아보이지만 solaris 9 이전에 모델입니다. 

 

 

Two-level Model ( 두 수준 모델)

Many-to-Many (다대다 모델)

다대다 모델인데 잘 보면 4개의 user 과 3개의 kernel thread 입니다. 이러한 상황에서는 멀티플렉싱(Multiplexing) 이 일어나게 됩니다.

 


Thread Libraries

이는 프로그래머에게 스레드를 생성하고 관리하게 해주는 API를 제공해주는 겁니다. 

 

두가지 구현

 

1. 완전히 애플리케이션 라이브러리 형태

- user space 에서만 동작, system 호출아님

 

2. kernel-level library  

-thread library 호출은 kernel system call 의미

 

 

다음 세 가지의 라이브러리가 많이 이용이 됩니다. 

 - POSIX Pthreads : user level, kernel level 둘다 제공 

 - Windows threads : OS level, Windows kernel level library

 - Java threads : JVM(Java Virtual Machine) , 깔려있는 OS 에 영향을 받음

 

 

 

Pthreads 

: 실제 구현이 아니라 어떻게 구현해야하는지를 명시,

POSIX standard(IEEE 1003.1c) API

 

 

Pthreads Example 

총합을 내는 예시

이 예제에서는 하나의 pthread가 생성해서 sum을 합니다. 만약 여러개를 쓴다면 한 pthread 는 0~8까지 더하고 어떤 pthread는 또 9~12 까지 더해서 각각 계산을 해서 나중에 합치는 방식도 사용할 수 있을 겁니다. 그래서 위에 int sum 에 있는 주석을 보면 sum 데이터가 스레드에게 공유되는 형태라고 적혀있는 겁니다. 

 

그리고 runner 라는 함수도 있습니다. 스레드가 이 함수를 콜합니다. 

 

tid는 스레드의 id , attr 는 스레드의 속성을 가집니다. 

 

-스레드를 생성하기 위해 속성을 가져오고 

-스레드를 생성하는 데 id, 속성 runner ,argument variable 이 있습니다. 

-스레드가 runner 함수를 호출하는데 이에 필요한 파라미터가 argv[1] 입니다.

 

코드 컴파일

여기서 wait 은 pthread 가 생성되고 runner 함수가 실행되고 exit 될 때까지 wait 합니다. 이게 pthread-join 입니다. 이 tid를 기다린다는 의미입니다.

 

그럼 아래 사진의 의미는 스레드 10개를 생성해서 기다린다는 의미일겁니다.

 

 

□Windows Threads

:Pthreads 와 유사

"windows.h" 파일 include -> 커널 레벨,OS 레벨에서 제공

□Java Threads

:애플리케이션 영역에서 실행되는 거처럼 보임, JVM이 thread생성, JAVA가 thread 기반 , 특이한 방식, OS의 특성을 그대로 사용


Implicit Threading (암묵적 스레딩)

 

다중 코어를 사용할 수록 이를 활용하는 다중 스레드 프로그래밍도 당연히 많아집니다.

이를 사용자가 개발하는 것explicit thread라고 하고 컴파일러가 제공해 주는 것 implict threading 이라고 합니다.

직접 프로그래머가 하기에는 스레드를 제대로 컨트롤 하기는 어렵습니다. 그렇기에 암묵적 스레딩의 대표적인 세 가지 방법에 대해서 알아보겠습니다.

 

1. Thread Pools

2. OpenMP

3. Grand Central Dispatch (Mac OS X and ios )

 

 

Thread Pools

: 시작 시점에 여러 개의 스레드를 미리 만들어 놓고 이 스레드들을 pool 에 넣어둡니다. 프로세스 스레드가 실행이 되면서 이 스레드들을 활용합니다. 

 

장점은 만들어 놓는거기 때문에 활용이 빠릅니다. 

그리고 사용하는 스레드의 수에 제한을 두는 효과가 있습니다.

thread pool 을 사용하는 과정

Thread 요청을 하면 Thread object를 만들고 메모리 리소스를 할당하게 되는데 thread pool 을 사용하면 이 과정이 필요없게 됩니다. 요청을 하면 바로 스레드 풀에서 가져와서 사용하게 됩니다.

스레드 풀 사용 과정 

                

 

 

OpenMP

: compiler directives(컴파일러가 스레드사용을 도와줌)

중요) 이 곳에 멀티 스레드 대상이 되는 코드를 적어놓으면 됩니다.(병렬 처리)

예를 들면 다음과 같습니다.

병렬처리가 되는 코드 부분

 

All Processors share the same memory , 모든 프로세서가 같은 메모리를 공유합니다. 

Intel, Microsoft, IBM, HP 에서 나오는 대형 컴퓨터들은 다 OpenMP 방식을 지원해주고 있습니다.

멀티 스레드 형식으로 fork 하고 Join으로 결과를 다 받을 때까지 기다립니다.

 

 

Grand Central Dispatch

parallel sections - OpenMP와 동일하게 병렬처리 하는 영역을 지정합니다. 


 "^{}" 이렇게 블럭 형식으로 표시합니다. ^{ printf("I am a block");} 

 

이 범위를 dispatch queue에 넣어서 가용 스레드가 있다면 그 가용 스레드에 할당돼서 사용됩니다. 다음과 같은 다양한 큐가 존재합니다.

 


Issues in designing multi-threading programs

 

- Semantics of fork() and exec() system calls

- Signal handling 

- Thread cancellation of the target thread

- Thread-local storage

- Scheduler Activations

 

 

 

 

Semantics of fork() and exec() system calls

 

: exec()는 스레드든 프로세스 레벨이든 동일합니다. 하지만 fork()은 다릅니다.

스레드 레벨에서 fork()을 할 경우 사용한 스레드만 복사가 되는지 아니면 모든 스레드가 새로운 프로세스에 복사가 되는지 두가지가 있습니다. 

 

-> 모든 thread를 복사하는 것도 있고 fork()을 호출한 thread만 복제하는 것도 있습니다. (UNIX는 두가지 기능의 fork()다 가집니다.)

 

 

□Signal handling 

 

: 어떤 프로세스에 이벤트를 보내기 위해서 시그널 핸들링을 사용합니다. 수신측에서는 이벤트를 처리하기 위해 시그널 핸들러가필요합니다. 그리고 비동기식 (asynchronized) 또는 동기식(synchronized) 일 수 있습니다.

 

기본적으로 커널에서 제공하는 defalut signal handler  이 있고 

사용자가 지정해서 사용하는 user-defined signal handler 가 있습니다. 

 

defalut signal handler는 override 의 형태로 구현할 수 있습니다.

 

전송하는 스레드가 뭐냐에 따라서 특정 스레드나 모든 스레드에 전송할 수 있습니다. 

 

 

Thread Cancellation

: 스레드 삭제니깐 당연히 특정 스레드가 명시가 되어 있어야 합니다.

비동기 삭제와 동기 삭제가 있습니다. 

비동기식 기다림없이 바로 삭제합니다.  -> 시스템 자원을 모두 회수하지 못 한 채로 끝나기도 합니다.(큰 문제) 

동기식주기적으로 체크하면서 삭제할 게 있는지 살펴봅니다. 삭제될 스레드는 체크를 당할 때 까지 기다려야 합니다.

 

스레드 취소에 대한 제한도 걸 수가 있습니다.

Deferred는 체크를 해서 어느 시점에 취소가 일어납니다. 그럼 그 시점은 어떻게 설정 할까요? 

pthread 에서는 pthread_testcancel() 이라는 함수로 cleanup handler 가 스레드 삭제를 해줍니다. 

 

 

Thread-Local Storage(TLS)

 

: 동일 process 에서는 다음과 같이 동일한 자원을 사용합니다. 

 

그러면 TLS 는 무엇일까요? 데이터를 공유하는 게 아니라 자기 자신만의 데이터 공간이 TLS 입니다. 자기 자신만 엑세스가 가능한 데이터 영역인 겁니다.  그렇다고 local variables(지역 변수) 와는 차이가 있습니다. 지역변수는 알다시피 함수내에서 동작하고 엑세스가 가능한 건데 TLS는 이와 달리 모든 곳에서 엑세스 할 수 있는 전역변수입니다.  (static data 와 유사) 

 

 

 

Scheduler Activations

: 사용자 스레드 레벨과 커널 스레드 레벨과의 통신을 하는 매커니즘 입니다.

 

위 그림을 보면 사용자 스레드와 커널 스레드 사이'LWP(lightweight process)' 라는 자료구조를 가집니다. 응용 입장에서 보면 LWP 는 사용자 스레드를 수행하기 위한 가상 프로세서(virtual processor) 처럼 여겨도 됩니다.  그리고 이는 커널에서 사용자로 upcalls 하는 걸 보여주고 있습니다.

 

upcall의 매커니즘에 대해 자세하게 살펴보도록 하겠습니다. 

 

-LWP 

: 사용자 스레드와 커널 스레드을 연결해주는 커널에서 애플리케이션에 제공하는 자료구조입니다. 아래의 그림을 보면 사용자 스레드와 커널 스레드 사이를 L 이 연결해주고 있는 걸 볼 수 있습니다. 커널은 Thread schedular와 함께 실제 Physical 한 프로세서들과 바인딩되어 있는 걸 볼 수 있습니다.

Scheduler Activations

이 개념이 왜 나왔을까요? 

애플리케이션은 사용자 스레드 레벨에 대해 부족한 정보를 가지고 있었습니다.(커널은 알지만) 커널도 사용자 스레드 레벨에 대한 부족한 정보를 가지고 있었죠. 시스템 콜로만 알고 있습니다. 

 

: 그래서 이 둘 사이에 정보를 원활히 교환할 수 있는 매커니즘이 필요했는데 이가 Scheduler Activation 매커니즘입니다.

 보면 사용자 스레드가 시스템 콜에 의해서 프로세서가 동작이 필요하다고 시스템 요청을 합니다. 커널에서는 위와 같이 프로세서의 상태에 대한 변경이 있고 이를 사용자 스레드에 전해줍니다.  

 

그래서 이처럼 커널이 사용자로 정보를 전달해주는걸 upcall, 그리고 사용자에서 커널로 가는 건 원래처럼 system call 이라고 합니다.

 

 

Scheduler Activations의 동작 예

a 스레드가 동작을 합니다. 이게 입출력 동작이라고 합시다. LWP 가 할당되어 system call 이 됩니다. 그러면 커널에서 block이 됩니다. 

그리고 커널에서 새로운 스레드가 생성이 되어 upcalls이 이뤄집니다. (커널 레벨 스레드가 block 되었다는 정보를 줄겁니다) 대신 다른 uses level therd (b)를 동작시킵니다. 

 

이후 unblock 이 되는 경우 

unblock이 되면 사용자 레벨의 (b)스레드에 맵핑되어있던 c가 preempt 가 될 것 입니다. 그리고 upcall로 정보를 전달해줍니다. 그러고 c에 맵핑되어있던 (b) 스레드도 preempt 됩니다. 그리고 멈췄던 (a) 스레드가 resume (재시작) 될겁니다.


이렇게 챕터 4가 끝났습니다. 수고하셨습니다.

 

                                                                                                                                                                              

728x90
반응형

'공부 > 운영체제' 카테고리의 다른 글

운영체제7 Deadlock  (0) 2020.07.03
운영체제6 Process Synchronizaiton  (0) 2020.07.03
운영체제5 CPU Scheduling  (0) 2020.06.21
운영체제3 Processes  (1) 2020.06.14
운영체제_1  (0) 2020.04.18