[OS] Threads & Concurrency

2025. 4. 11. 20:38·Operating system

 

 

프로세스의 개념은 두 가지 특성을 포함:

 

자원 소유(Resource Ownership)
- 프로세스는 프로세스 이미지 및 리소스(메인메모리, I/O장치, 파일)를 hold하기 위한 가상 주소 공간을 포함   
- OS는 자원과 관련된 프로세스 간의 원치 않는 간섭을 방지하기 위한 보호 기능 수행


스케줄링/실행(Scheduling/Execution)
- 하나의 프로세스 실행은 다른 프로세스들과 인터리브(교차 실행)될 수 있다
- 프로세스는 실행 상태(running, ready..)와 스케줄링 정보(디스패치 우선순위)를 가짐
- 프로세스는 OS에 의해 스케줄되고 디스패치되는 실행 단위

 

두 가지 특성은 서로 독립적

dispatching 단위 : Thread  (= lightweight process)
resource ownership 단위 : Process (= task)

스케줄링/실행(디스패칭)의 단위는 스레드(=lightweight process)이고 

자원 소유의 단위는 프로세스이다

 

 

single-threaded approach: 하나의 프로세스당 하나의 실행 흐름만을 갖는 방식
 - MS-DOS는 단 하나의 사용자 프로세스만을 지원
 - 구버전 UNIX는 여러 사용자 프로세스를 지원

Multi-threaded approach

멀티스레딩(Multithreading) : OS가 하나의 프로세스 내에서 여러 개의 실행 흐름 동시에 지원하는 방식
 - Java 런타임 환경 : 하나의 프로세스 안에서 여러 스레드를 실행
 - Windows, Solaris, Linux 는 여러 프로세스를 지원, 각 프로세스는 다수의 스레드를 포함 가능

 

 

 

멀티스레드 환경에서 프로세스는 자원 할당의 단위이자 보호의 단위
프로세스 관련 요소:  
- 프로세스 이미지를 저장하는 virtual address space
- 다음 자원에 대한 protected access

   프로세서(CPU), 다른 프로세스들 (프로세스 간 통신을 위한), 파일, I/O 자원

 

 

스레드 요소:
- 실행 상태 (Running, Ready, Blocked) (TCB에 포함)
- 실행 중이 아닐 때를 위한 saved thread context (TCB에 포함)
- 실행 스택 (User stack(스레드 별)에 포함)
- 해당 프로세스의 메모리 및 자원에 대한 접근 권한 (PCB에 포함, 스레드 간 공유)

 

스레드가 실행 흐름의 단위이기 때문에, 프로세서 정보는 모두 TCB에 있다, PCB에는 자원에 대한 정보들이 있다

 

Process creation is heavy-weight

while thread creation is light-weight

 

응답성(Responsiveness)
프로세스의 일부가 차단되어도 실행을 계속할 수 있게 해줌

특히 UI에서 중요

자원 공유(Resource Sharing)
스레드는 동일한 프로세스의 자원을 공유하여 서로 간의 통신이 빠르고 효율적
shared memory나 message passing보다 더 쉬움

경제성(Economy)
프로세스 생성보다 생성 비용이 적게 듬
Thread switching은 프로세스 간 Context switching보다 오버헤드가 낮다

확장성(Scalability)
멀티스레드 프로세스는 멀티코어 아키텍처를 효과적으로 활용할 수 있다.

 

 

 

스케줄링과 디스패치가 스레드 단위로 이루지고 실행 관련 정보는 스레드 수준 데이터 구조에 저장


프로세스 내 모든 스레드에 영향을 주는 동작들
- 프로세스 중지하면, 해당 프로세스의 모든 스레드 함께 중지 → 모든 스레드가 같은 주소 공간을 공유하기 때문
- 프로세스를 종료하면, 해당 프로세스 내의 모든 스레드 함께 종료

 

 

스레드의 상태: Running / Ready / Blocked

스레드 상태 변화 관련 연산:
Spawn : 하나의 프로세스 내에서 한 스레드가  다른 스레드를 생성
Block : 스레드가 어떤 이벤트를 기다려야 할 경우, 해당 스레드는 blocked 상태로 전환
Unblock : blocked된 스레드가 기다리던 이벤트가 발생하면, 해당 스레드는 Ready queue로 이동 
Finish : 작업이 완료 시, register context와 stack이 할당 해제됨

 

 


여러 스레드의 Synchronization 필수 :
하나의 프로세스에 속한 모든 스레드는 같은 주소 공간과 자원을 공유
따라서 한 스레드가 자원을 변경하면,  다른 스레드들도 그 영향을 받게 됨

 

User Level Thread (ULT) :

어플리케이션 라이브러리에 의해 관리되는 스레드로 커널은 스레드의 존재를 인지하지 못한다

 

Many-to-One 모델 : 
여러 개의 User 스레드에 하나의 Kernel 스레드를 매핑하는 방식

 

장점

1. 스레드 전환 시 context switching이 필요하지 않아 전환이 빠르다
2. 스케줄링 우선순위를 프로그래머가 설정할 수 있다
3. 라이브러리로 돌아가기 때문에 어떤 OS에서도 실행 가능

단점
많은 시스템 콜이 블로킹됨  

OS가 개별 ULT를 인식하지 못하고, 하나의 커널 스레드만 관리하기 때문에

1. 커널 스레드가 블로킹되면, 그 위에서 동작하던 모든 ULT도 블로킹 되어 실행되지 못하게 됨

 

커널이 하나의 프로세스를 한 번에 하나의 프로세서에만 할당하기 때문에

여러 개의 스레드가 있어도 병렬 실행이 불가능

2. 멀티프로세서 환경의 장점을 활용할 수 없다 (확장성이 떨어진다)

 

 

단점 해결책

1. 멀티프로세스로 애플리케이션 작성 : 스레드의 장점을 없애는 것
   - 프로세스 전환은 스레드 전환보다 훨씬 큰 오버헤드가 발생

2. 자켓팅(Jacketing)

 - 블로킹 시스템 콜을 논블로킹 시스템 콜로 래핑하는 것  

 - 어떤 스레드가 시스템 콜을 하려 할 때,

    지금 당장 실행 불가능하거나 시간이 걸릴 것 같으면 

    자기 자신을 스스로 Blocked 상태로 바꾸고, 준비된 스레드에게 CPU를 넘기는 것

    (커널 수준 x, ULT 라이브러리 내부 수준 o)

 

 

Kernel Level Thread (KLT) : 커널에 의해 관리되는 스레드

light weight process라고 하는 것은 kernel level 스레드이다

 

One-to-One 모델:

하나의 User 스레드에 하나의 Kernel 스레드를 매핑하는 방식

user-level 스레드를 생성하면, 해당하는 kernel 스레드도 함께 생성됨
애플리케이션 수준에서는 스레드 관리 코드가 필요 없으며, 단순히 커널 스레드 기능을 사용하는 API만 제공

각 user 레벨 스레드는 하나의 kernel 레벨 스레드에 1:1로 매핑

 

장점

1. 커널이 하나의 프로세스 내 여러 스레드를 여러 프로세서에 동시에 스케줄링 할 수 있어

    Many-to-one 방식보다 concurrency가 높다

2. 한 스레드가 blocked 되더라도, 커널이 같은 프로세스의 다른 스레드를 대신 실행할 수 있다

단점
1. 스레드 간 제어를 전환할 때, context switch해야 하므로 오버헤드가 발생
   이 오버헤드 때문에, 프로세스당 생성 가능한 스레드 수가 제한될 수 있음

 

 

Combined Approaches : Many-to-Many모델
- 스레드 생성은 user space에서 처리, 대부분의 스케줄링과 동기화 작업도 사용자 수준에서 수행
- 여러 개의 ULT가 일정 수(ULT 스레드보다 같거나 작은 양)의 KLT에 매핑
 - 오류 많고, 관리의 오버헤드가 커서 현재는 잘 사용되지 않음


싱글-코어 시스템에서의 councurrent execution:  
동시성은 둘 이상의 작업을 번갈아 수행하여 마치 동시에 수행되는 것 처럼 보이게 하는 것

멀티-코어 시스템에서의 parallelism:  
병렬성은  둘 이상의 작업을 물리적으로 동시에 수행하는 것

 

 

멀티코어 시스템의 challenges:
(1) 작업 식별 (Identifying tasks)
-  병렬화 가능한 영역을 찾아야 함  
- 작업들이 서로 독립적이어야 함
(2) 균형 (Balance)
데이터 분할(Data splitting)
- 데이터를 나누어 별도의 코어에서 실행할 수 있어야 함
(3) 데이터 의존성 (Data dependency)
- 작업 간 데이터 의존성을 고려하여 실행을 동기화해야 함
(4) 테스트 및 디버깅 (Testing and debugging)
- 단일 스레드 애플리케이션보다 더 어려움

 

 

데이터 병렬성(Data parallelism)

– 데이터의 하위 집합들을 여러 코어에 분산시켜, 각 코어에서 동일한 연산을 수행
작업 병렬성(Task parallelism)

– 동일한 데이터를 여러 코어에 분산시켜, 각 코어에서 고유한 작업을 수행

 

 

Amdahl’s Law :

추가적인 코어 사용에 따른 성능 향상 정도를 나타는 법칙

 

최대 속도 향상은 1 / S에 수렴함
- S = 5%, N = 2 → 속도 향상(Speedup) = 1.9  
- S = 25%, N = 2 → 속도 향상 = 1.6  
- S = 50%, N = 2 → 속도 향상 = 1.3  


Pthreads Example

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

int sum; /* this data is shared by the thread(s) */
void *runner(void *param); /* threads call this function */

int main(int argc, char *argv[])
{
    pthread_t tid;        /* the thread identifier */
    pthread_attr_t attr;  /* set of thread attributes */

    /* set the default attributes of the thread */
    pthread_attr_init(&attr);

    /* create the thread */
    pthread_create(&tid, &attr, runner, argv[1]);

    /* wait for the thread to exit */
    pthread_join(tid, NULL);

    printf("sum = %d\n", sum);
}

/* The thread will execute in this function */
void *runner(void *param)
{
    int i, upper = atoi(param);
    sum = 0;

    for (i = 1; i <= upper; i++)
        sum += i;

    pthread_exit(0);
}

 

 

#include <pthread.h>
#include <stdio.h>

int value = 0;
void *runner(void *param); /* the thread */

int main(int argc, char *argv[])
{
    pid_t pid;
    pthread_t tid;
    pthread_attr_t attr;

    pid = fork();

    if (pid == 0) { /* child process */
        pthread_attr_init(&attr);
        pthread_create(&tid, &attr, runner, NULL);
        pthread_join(tid, NULL);
        printf("CHILD: value = %d", value); /* LINE C */
    }
    else if (pid > 0) { /* parent process */
        wait(NULL);
        printf("PARENT: value = %d", value); /* LINE P */
    }
}

void *runner(void *param) {
    value = 5;
    pthread_exit(0);
}
'Operating system' 카테고리의 다른 글
  • [OS] CPU Scheduling #1
  • [OS] Introduction
  • [OS] Processes
  • [OS] Virtual Memory
vysryoo
vysryoo
  • vysryoo
    vysryoo
    vysryoo
  • 전체
    오늘
    어제
    • 분류 전체보기 (129)
      • Python (20)
      • Data structure (12)
      • Algorithm (14)
      • Operating system (18)
      • Programming language theory (12)
      • Computer architecture (6)
      • Softeware engineering (8)
      • Multicore (2)
      • Data Base (3)
      • Problem solving (24)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
vysryoo
[OS] Threads & Concurrency
상단으로

티스토리툴바