[OS] - Thread 스레드에 대해 알아보자

2024. 3. 10. 23:36·etc
728x90

Thread?

- A single unique execution context

- Mechanism for concurrency (동시성) + can also run in parallel (병렬성)

- Protection (보호) → 쓰레드 간 자원 접근을 제어하고 안전하게 관리하기 위한 메커니즘

 

MTAO (multiple things at once)

- 운영 시스템은 프로세스, 인터럽트, 백그라운드 시스템 유지 등 다양한 것들을 한 번에 핸들링할 수 있어야 함

- 네트워크 서버, 병렬 프로그램, UI를 지닌 프로그램, 그리고 network/disk bound 프로그램도 마찬가지

→ 이러한 것들을 가능하게 해주는 것이 바로 Thread

스레드는 동시성의 유닛이고, 각각의 쓰레드는 하나 혹은 한 태스크를 표현할 수 있음!

 

Multiprocessing vs Multiprogramming

여러 CPU가 일들을 하나씩 맡아서 작업하면, 같은 시각에 실행되는 프로세스가 여러 개

→ Mutiprocessing

 

한 CPU 내에서 일들이 서로 번갈아가면서 하거나 툭툭 끊어져서 진행, 즉 같은 시각에 실행되는 프로세스는 단 하나

→ Multiprogramming / Multithreading

 

Concurrency는 Parallelism이랑 같지 않다!

Concurrency는 여러 일을 한 번에 제어할 수 있는 것

Parallelism은 여러 일들이 동시에 실행하는 것

 

예를 들어, 싱글 코어 (CPU가 한 개인 경우)에서 두 스레드가 실행된다면, 이는 동시적인 것이지 병렬적인 것이 아님.

 

Thread의 3가지 상태

- Running : 현재 실행되고 있음

- Ready : 실행되기 위해 기다리고 있음

- Blocked : 입출력 작업을 수행, 동기화 등 cpu를 필요로 하지 않는 상황에서 자원을 낭비하지 않음

 

 

Blocked? 그냥 Running과 Ready만 있어도 되는 게 아닌지?

→ 예를 들어 입출력 완료를 첫 번째 스레드가 기다리고 있다고 해보자. 이 첫번째 쓰레드를 ready 상태로 바꾼다면 cpu 자원을 낭비하게 될텐데, 사실 입출력이 완료되길 기다리는 동안에는 굳이 cpu를 점유할 필요가 없다. 따라서 완료가 될 때가지 blocked 상태로 있는다면 다른 쓰레드가 먼저 cpu를 쓰면서 효율적인 이용이 가능할 것이다.

 

pthreads

병렬적으로 작동하는 소프트웨어의 작성을 위해서 제공되는 표준 API인 pthreads를 통해 스레드의 동작을 파악할 수 있다. pthreads 라이브러리 내장 함수를 알아보도록 하자.

 

1) 생성

include <pthread.h>

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);

 

스레드를 생성하는 함수이다.

 

첫 번째 인자는 스레드를 가리키는 포인터,

두 번째 인자는 스레드의 특정 옵션을 설정(대부분의 경우 NULL 입력),

세 번째 인자는 스레드가 수행할 함수,

네 번째 인자는 세 번째 인자에 들어가는 함수가 필요로 하는 내부 인자이다.

 

2) 종료

void pthread_exit(void *value_ptr);

 

스레드를 종료할 때 쓰는 함수이다. 보통 인자에는 NULL이나 0이 들어간다.

 

3) 조인

int pthread_join(pthread_t thread, void **value_ptr);

 

타깃 스레드 (첫 번째 인자)가 종료될 때까지 기다리는 함수라고 생각하면 쉽다. 만약 메인 스레드에서 파생된 스레드들보다 메인 스레드가 먼저 종료된다면, 원하는 작업을 끝내지 못한 채 종료될 수 있기 때문이다. 두 번째 인자는 조인 함수의 반환값을 담을 포인터인데, 이 값을 통해 메인 스레드에서 다른 스레드의 상태를 확인할 수 있다. 또 이렇게 전체 업무를 여러 개의 작은 업무로 나누어 처리하고 합치는 과정을 Fork-Join Pattern이라고 한다.

 

pthread 실행 예제

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

int common = 162;

void *threadfun(void *threadid) {
    long tid = (long)threadid;
    printf("Thread #%lx stack: %lx common: %lx (%d)\n", tid, (unsigned long) &tid, (unsigned long) &common, common++);
    pthread_exit(NULL);
}

int main(int argc, char *argv[]) {
    
    long t;
    int nthreads = 2;

    // 인자를 입력하면 그만큼 쓰레드를 생성함. Default: 2
    if (argc > 1) {
        nthreads = atoi(argv[1]); //argument to integer
    }

    pthread_t *threads = malloc(nthreads*sizeof(pthread_t)); // 쓰레드의 개수만큼 위치 동적 할당
    printf("Main stack: %lx, common: %lx (%d)\n", (unsigned long) &t, (unsigned long) &common, common);
    for (t = 0; t < nthreads; t++) {
        int rc = pthread_create(&threads[t], NULL, threadfun, (void *)t);
        if (rc) { // 보통 쓰레드 생성에 에러가 발생한다 -> return value != 0
            printf("ERROR; return code from pthread_create() is %d\n", rc);
            exit(-1);
        }
    }

    for (t = 0; t<nthreads; t++) {
        pthread_join(threads[t], NULL);
        printf("%ld\n", t);
    }

    pthread_exit(NULL);
    return 0;
}

 

스레드의 전체 흐름을 알아볼 수 있는 예제 코드이다. 실행 파일을 만들어 생성할 쓰레드의 개수를 입력해 주면 어떤 순서로 스레드가 실행되고 종료되는지를 확인해 볼 수 있다.

 

Review Point

만약 위 코드를 통해 스레드를 4개 생성한다고 했을 때, 아래 질문에 대답해 보자.

 

1. 이 프로그램에서 총 몇 개의 스레드가 사용되었는가?

- 5개가 사용되었다. 한 개의 메인 스레드와 4개의 생성된 스레드.

2. 메인 스레드는 다른 스레드들의 생성 순서와 동일한 순서로 조인하는가?

- 위 코드에서는 for문을 통해 순차적으로 조인하고 있다. 그러하다.

3. 생성된 스레드들은 그들이 만들어진 순서대로 종료되는가?

- 아니다. 위 코드 상에서는 먼저 처리되는 스레드는 바로 종료된다.

4. 프로그램이 다시 실행된다면 결과가 달라지는가?

- 그러하다. 운영체제의 스레드 스케줄러의 스케줄링에 의해 결정된다.

728x90
저작자표시 비영리 변경금지 (새창열림)

'etc' 카테고리의 다른 글

[GitHub] master branch를 main branch로 변경하기  (0) 2024.11.22
[GitHub] 깃허브 기여하기 - Fork, Pull Request(PR)  (0) 2024.10.15
[GitHub] 깃허브 시작하기 - Repository 생성  (4) 2024.09.19
[GitHub] MacOS 업데이트 후 Git 에러가 발생할 때 (xcrun: error)  (0) 2022.03.13
'etc' 카테고리의 다른 글
  • [GitHub] master branch를 main branch로 변경하기
  • [GitHub] 깃허브 기여하기 - Fork, Pull Request(PR)
  • [GitHub] 깃허브 시작하기 - Repository 생성
  • [GitHub] MacOS 업데이트 후 Git 에러가 발생할 때 (xcrun: error)
100두산
100두산
출발하게 만드는 힘이 동기라면, 계속 나아가게 만드는 힘은 습관이다.
  • 100두산
    정상에서 보자 ✈️
    100두산
  • 전체
    오늘
    어제
    • 분류 전체보기 (126)
      • Life (6)
        • living (1)
      • Research (6)
      • AI (20)
      • Dev (45)
        • iOS (28)
        • Web (4)
        • flutter (9)
        • etc (4)
      • PS (Problem Solving) (23)
      • Computer Science and Engine.. (21)
        • Data Structures and Algorit.. (13)
        • OOP (Object Oriented Progra.. (8)
      • etc (5)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 글쓰기
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    자료구조
    SKT
    xcode
    AI
    티스토리챌린지
    c++
    파이썬
    D3
    Python
    알고리즘
    PS
    백트래킹
    ios
    SKTelecom
    백준
    swift
    Challenger
    오블완
    TIP
    BOJ
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
100두산
[OS] - Thread 스레드에 대해 알아보자
상단으로

티스토리툴바