열정 실천

Thread 스레드 - 하나의 프로세스 안에 멀티스레드 본문

CS/OS

Thread 스레드 - 하나의 프로세스 안에 멀티스레드

구운오니 2024. 9. 13. 17:23
728x90
Thread 스레드

 

Thread는 프로그램이 실행되는 최소단위로 하나의 프로세스 안에 여러 개의 스레드가 존재할 수 있다. 

하나의 프로세스 안에 있는 스레드들은 많은 정보를 공유하는데,, 

 

우선 PCB, PCB는 하나의 프로세스에 해당하는 내용이기에 스레드마다 PCB가 존재하는 것이 아니다. 

스레드는 각각의 PC와 register 값을 제외한 PCB 데이터는 모두 공유한다. 

 

 

 

 

 

또한 스레드는 메모리 세그먼트 중 Stack을 제외한 모든 자원을 공유한다. 👇👇👇 (code, data, heap, files 공유)

출처 : 공룡책

 

 

 

 

 

멀티 프로세서와 멀티 스레드의 차이

(Concurrency vs Parallelism)

 

 

멀티 프로세서는 CPU가 여러 개임을 뜻하고 

멀티 스레드는 하나의 CPU 안에 여러 개의 실행 과정(스레드)가 있는 것이다. 

 

멀티 프로세서는 실제로 여러 작업이 병렬적으로 "동시에" 실행되고 (Parallelism)

멀티 스레드는 스케쥴링을 통해 여러 작업을 번갈아 수행하며 모든 작업을 진행시키는 것이다. 이는 여러 작업이 동시에 수행되는 것처럼 보이는데 이를 "병행성"이라고 한다. (Concurrency)

 

**멀티 프로세서의 프로세서는 프로세스가 아님!!

    # 프로세스 vs 프로세서 

    프로세스는 실행 중인 프로그램

    프로세서는 컴퓨터의 중앙 처리 장치인 CPU를 지칭하는 하드웨어이다. 

 

앞서 공부했던 fork()와 exec()을 통해 여러 개의 프로세스를 실행하는 것 또한 "병행성"이다. 

 

  • 하나의 CPU에서 여러 프로세스가 번갈아 실행되는 것은 병행성.
  • 여러 CPU 코어에서 여러 프로세스가 동시에 실행되는 것은 병렬성.

 

 

 

-

 

 

 

스레드 생성 API in Linux 

 

📌 pthread_create :: 새로운 프로세스를 생성하는 함수

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

 

인자 1 : 생성된 스레드의 ID를 저장할 변수의 포인터 

인자 2 : 스레드의 특성을 설정할 때 사용 (주로 NULL)

인자 3 : 스레드가 생성되고 나서 실행할 함수 

인자 4 : 세 번째 인자에서 호출되는 함수에 전달하고자 하는 인자

 

📌 pthread_join :: 스레드가 종료될 때까지 호출한 스레드가 기다리도록 하게 함

pthread_join(pthread_t th, void **thread_return)

 

인자 1 : 스레드 ID. 이 ID가 종료할 때까지 실행을 지연

인자 2 : 스레드 종료시 반환값

 

 

스레드 생성 실습코드 

 

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

void* thread_function(void* arg){
        printf("Hello from the thread!\n");
        return NULL;  //스레드 함수는 반드시 void*를 반환 (여기서는 NULL)
}

int main(){
        pthread_t thread; //스레드 식별자
        int result;       //pthread 함수 호출의 반환 값을 저장할 변수

        //새로운 스레드 생성 / 실패 시 에러 메세지 출력
        result = pthread_create(&thread, NULL, thread_function, NULL);
        if(result != 0){
                fprintf(stderr, "Error creating thread\n");
                return 1;
        }

        //메인 스레드가 새로 생성된 스레드가 종료될 때까지 기다리기
        result = pthread_join(thread, NULL);
        if(result != 0){
                fprintf(stderr, "Error joining thread\n");
                return 2;
        }

        //스레드가 정상적으로 종료된 후 실행되는 코드
        printf("Thread has finished executing\n");
        return 0;
}

코드 실행 결과

 

 

 

 

 

 

 

스레드를 어떻게 효율적으로 사용할까?

 

 

 

쓰레드 풀  (Thread Pool)

 

미리 일정 개수의 쓰레드를 생성하여 쓰레드 풀에 저장하고, 새로운 작업이 도착할 때마다 쓰레드를 생성하는 대신 만들어 놓은 쓰레드를 사용한다. 때문에 작업이 밀려도 빠르게 응답할 수 있다. 또 스레드가 하나의 작업을 끝내면 종료하지 않고 계속해서 재사용되기 때문에 자원 낭비도 줄일 수 있다. 

 

무한정 스레드를 생성하게 되면 메모리 부족, 과부화 등 스레드 관련 문제가 발생할 수 있기 때문에 항상 스레드 개수를 제한하고 그 안에 스레드를 생성할 수 있도록 해야한다. 

 

 

스레드 풀 웹 서버

 

스레드 풀(Thread Pool)이 적용된 웹 서버는 다수의 클라이언트 요청을 효과적으로 처리하기 위해 미리 생성된 스레드 그룹을 사용하여 요청을 병렬로 처리하는 방식의 서버다. 이러한 서버 구조는 동시 요청 처리 성능을 최적화하면서도 시스템 자원 사용을 효율적으로 관리하는 데 중요한 역할을 한다. 

 

스레드 풀 웹 서버의 작동 원리

  1. 클라이언트 요청: 클라이언트가 웹 서버에 HTTP 요청을 보내면, 서버는 해당 요청을 대기열에 추가한다. 
  2. 스레드 풀에서 작업 할당: 스레드 풀이 미리 생성되어 있고, 대기 중인 스레드가 요청 대기열에서 작업을 하나씩 가져와 처리한다. 
  3. 작업 처리: 각 스레드는 독립적으로 클라이언트 요청을 처리하며, 요청이 완료되면 해당 스레드는 다시 스레드 풀로 반환되어 다음 요청을 처리할 준비한다. 
  4. 응답 전송: 작업을 완료한 스레드는 클라이언트에게 결과를 응답으로 반환하고, 풀에서 대기 중인 다른 요청을 처리한다. 
728x90