오른쪽 그림과 같이, 프로세스 메모리 공간에 stack이 여러개 생기는 구조이다. (각 스레드별 stack)
각 스레드는 모두 data, heap, text에 접근할 수 있으므로, static이나 global 변수 같은 거 접근 가능한 뜻임.
만약 한 스레드가 글로벌 변수++하면, 다른 스레드가 접근했을 때도 ++된 걸로 나온다는 뜻
※ 프로세스와 스레드의 가장 큰 차이점은공유하는 데이터 공간의 유무이다. 한 프로세스에서 비롯된 스레드들이더라도 자신만의 스택, 레지스터 값, PC값을 갖고있어서 아예 따로 실행 가능하다.
◆ Thread 장점
왜 스레드를 쓰는지에 관한 이야기.
Responsiveness(응답성) - 실행 흐름이 나뉘어져 있으므로, 프로세스의 일부가 block되어도 나머지는 계속 실행 가능하다.
Resource Sharing(자원 공유) - 스레드 사이에서는 데이터 공유가 쉽다. (글로벌 변수 두고 그걸로 하면 되니까)
Economy(경제성) - 프로세스 만드는거보다 스레드 만드는게 더 비용이 적게 든다. (한 메모리 공간을 공유하고, 일부 리소스들도 공유하기 때문) 스레드 스위칭 역시 컨텍스트 스위칭에 비해 오버헤드가 적다.
Scalability(확장성) - 각 스레드가 각기 다른 프로세서에서 실행할 수 있기 때문에, 멀티 코어 구조에서 극대화된 이득을 가질 수 있다. (싱글 스레드로 하면, 코어가 몇 개이이든 간에 프로세스가 코어 한 개에서만 돌음. 남는 코어 많아도 이득을 못 봄)
◆ Parallelism vs Concurrency
Parallelism: 두 개 이상의 코어에서 task들이 실제로동시에 돌아가는 것
Concurrency: task들이 동시에 돌아가는 것 처럼 보이는 것
Tn 은 n번 task를 의미.
위 그림처럼 하나의 코어가 여러 스레드를 번갈아가면서 수행함으로써, 동시에 실행되는 것처럼 보이게 할 수 있다. (Concurrent)
아래에서는 여러 개의 코어가 각 스레드를 실제로 동시에 수행하는 방식이다. (Parallel)
※ Hyperthreading: Parallelism하는게 아니라 Hardware가 context Swtching처럼 thread 빠르게 전환 하는 것.
◆ Parallelism
Parallelism에는 두가지 종류가 있다
Data parallelism : 하는 작업은 똑같은데, 데이터만 분담해서 처리하는 것. ex) 많은 데이터들을 GPU에 때려 넣어서 병렬 처리(계산)하는 것.
Task parallelism : 각각 하는 작업이 다른 것. 작업을 분담한 것. 데이터는 공유해서 쓰지만 패스별로 나누어서 사용
◆Multicore Processing
하나의 작업을 위해 여러 개의 CPU 코어를 사용하는 것
원래는 CPU 코어가 하나밖에 없었고 코어 자체의 성능을 발전시키고자 노력했는데,
계속 기술이 발전하다보니 한 코어로 처리할 수 있는 스피드의 HW적 한계에 도달하게 됨.
→ CPU에 여러 개의 코어를 넣어서 동시에 많은걸 처리하자!
멀티 코어에 멀티 스레딩을 구현 하는 건 프로그래머의 몫임. 코어가 여러 개 있다는 걸 인지하고 구현하지 못하면 하드웨어를 최대한 활용하지 못하는 것
따라서 이건 멀티 스레딩으로 구현할 수 있어! 라고 한다면, 그렇게 하는게 성능적으로 좋다.
스레드 라이브러리 예시) POSIX Pthreads, Windows threads, Java threads
물론, 그만큼 주의해야할 사항들이 있다.
Identifying tasks : 각 task들을 parallel하게 실행하려면 서로 독립적이여야 한다.
Balance: 각 task들의 size, runtime 등이 비슷해야 한다.
Data splitting: Application이 여러 task로 나뉘는 것처럼 data역시 task에 따라 분할되어야 한다.
Data dependency : 서로 다른 task가 같은 data를 read/write한다면 dependency가 생기게 되는데 이 때 synchronizaion을 해주어야 한다.
Testing and debugging : Single-threaded에서는 execution path가 매우 단순하지만 multi-threaded에서는 그렇지 않다. 작은 변화에도 execution path가 달라지기 때문에 test/debugging이 매우 어렵다.
< Amdahl's Law >
암달의 법칙 : 병렬 처리시 최대 어느정도의 성능 향상이 가능한지 계산하는 법칙.
S는 무조건 연속적으로 실행해야 하는 부분을, N은 코어의 개수를 의미한다.
ex)
원래 하나의 코어에서 실행하던 걸 두 개에서 실행한다고 하자.
무조건 연속적으로 실행해야 하는 부분이 25%라면, 다음과 같이 계산할 수 있다.1/(0.25+0.75/2) ≒ 1.6→ 실행 속도는 최대 1.6배까지 빨라질 수 있다는 의미이다.
어느 정도 최적화하느냐에 따라 우리가 얻을 수 있는 스피드가 달라진다.
따라서 프로그램 전체를 대상으로 최적화하느 것이 중요하다.
Ideal speedup: 전부 병렬화 가능한 경우를 의미함.
S의 비율이 늘어날수록, 코어가 늘어나도 speedup은 별로 안 늘어난다.
◆User thread vs Kernel thread
User thread: 유저 레벨의 스레드 라이브러리가 관리하는 스레드 유저 스레드는 실행되기 위해서는 반드시 OS 스레드와 연결이 되어야 함. 이유는, CPU에서 실행되는 단위는 OS 스레드이기 때문. 장점 :
OS 입장에서는 신경을 안 써도 되니 오버헤드가 적다
단점 :
안정성이 떨어진다.
한 프로세스 안에 1, 2, 3 스레드 3개가 있는데 만약 3번 스레드가 커널에게 trap을 걸어 I/O요청을 했을 때 3번 스레드 뿐만 아니라 1~3 스레드 전부가 waiting queue에 들어가게 된다. (프로세스 단위로 CPU가 할당되기 때문)
Kernel thread: 커널이 지원하는 스레드. 최신 OS들은 대부분 커널 스레드를 지원한다. 장점 :
기능상 커널에서 관리 하는 것이 더 신뢰성 있고 안정적
진정한 의미의 멀티스레드
단점 :
유저 모드에서 커널 모드로 계속 바꿔줘야 하기 때문에 성능이 저하
◆ Multithreading Models
유저 스레드들과 커널 스레드들 사이에 관계가 생길 것인데, 이 관계에 따라 다음과 같이 멀티스레딩 모델을 분류한다.
[user]-to-[kernel]
Many-to-One 모델 : 유저 스레드 여러 개가 커널 스레드 하나에 매핑되는 모델 - 한 스레드가 갑자기 block 되면, 커널 스레드 자체가 block 될 것. - 한 번에 하나의 유저 스레드만 커널에 접근할 수 있기 때문에, 멀티코어 시스템에서 병렬적인 수행을 할 수가 없다.
One-to-One 모델 : 유저 스레드 하나가 커널 스레드 하나에 매핑되는 모델
- 대부분 이 방식을 사용한다. 대표적으로 Windows와 Linux에서도 사용함. - 멀티코어 시스템에서 동시에 여러 스레드를 수행할 수 있도록 해준다. - 그러나 유저 스레드를 늘림에 따라 커널 스레드도 똑같이 늘어나는데, 커널 스레드를 생성한다는 것은 오버헤드가 큰 작업이므로 성능 저하가 발생한다. (스레드 개수 제한 등의 방식이 필요하다)
Many-to-Many 모델 : 여러 유저 스레드에 더 적거나 같은 수의 커널 스레드가 대응하는 모델 - 비교적 자유도가 높으나, 구현하기 복잡하다.
◆ Thread Libraries
실제로 스레드를 만들 때는 스레드 라이브러리를 이용한다.
이때 유저 레벨 라이브러리를 사용하거나, 커널 레벨 라이브러리를 사용할 수 있다.
스레드 라이브러리 예시)
■ Pthread
: POSIX 스탠다드를 따르는 스레드 라이브러리.
■ Pthread 사용 예시
■ Pthread - 스레드 취소 (스레드 강제종료)
취소 모드에 따라 스레드의 취소 요청을 어떠한 시점에 처리할지를 결정하게 된다.
• 지연 취소(Deferred cancellation) : 기본값. 시스템상에서 해당 스레드의 다음 취소 시점(Cancellation point)까지 대기
- pthread_cond_wait(), pthread_join() 그리고 pthread_testcancel() 과 같은 함수가 취소 시점을 제공하므로 해당 함수 호출 때까지 대기
- 시스템 마다 지원하는 취소 시점(Cancellation point)이 상이 하므로 원하는 취소 동작을 수행할 수 있는지 확인 필요
• 비동기 취소(Asynchronous cancellation) : 취소 요청시 즉시 처리 시도(지연 가능성 있음)