쓰레드 생성

Jaemyeong Lee·2024년 12월 6일
0

1. 쓰레드란?

쓰레드(Thread)는 프로그램 내에서 실행되는 가장 작은 실행 단위입니다. 프로세스 안에서 실행되며, 프로세스의 메모리 공간(코드, 힙, 데이터)을 공유합니다. C++에서는 <thread> 라이브러리를 사용하여 멀티스레드 프로그래밍을 구현할 수 있습니다.


2. 쓰레드의 기본 구조

2.1 헤더 파일 및 네임스페이스

#include <iostream>
#include <vector>
#include <thread>
using namespace std;
  • #include <iostream>: 콘솔에 출력하기 위해 사용.
  • #include <vector>: 여러 쓰레드를 관리하기 위해 벡터 컨테이너를 사용.
  • #include <thread>: C++ 표준 쓰레드 클래스(std::thread)를 사용.
  • using namespace std;: 표준 라이브러리 사용 시 std::를 생략.

2.2 쓰레드 실행 함수

void HelloThread(int i)
{
    cout << "Hello Thread " << i << endl;
}
  • HelloThread:
    • 쓰레드가 실행할 함수로, 매개변수 i를 받아 "Hello Thread"와 함께 출력.
    • 각 쓰레드는 이 함수를 실행하며, i를 통해 고유한 값을 전달받음.

3. 메인 함수 코드 분석

3.1 쓰레드 관리

int main()
{
    vector<thread> threads; // 쓰레드 객체를 관리할 벡터
  • vector<thread>:
    • 여러 쓰레드를 동적으로 생성하고 관리하기 위해 벡터 사용.
    • 각 쓰레드 객체를 벡터에 저장하여 반복적으로 제어 가능.

3.2 여러 쓰레드 생성

    for (int i = 0; i < 10; i++)
    {
        threads.push_back(thread(HelloThread, i));
    }
  • 반복문:
    • 총 10개의 쓰레드를 생성.
    • thread(HelloThread, i):
      • HelloThread 함수와 i 값을 매개변수로 전달하여 쓰레드 생성.
    • threads.push_back():
      • 생성된 쓰레드를 벡터에 추가하여 관리.

3.3 메인 쓰레드 출력

    cout << "Hello Main!" << endl;
  • 메인 쓰레드 동작 확인:
    • Hello Main!은 메인 쓰레드에서 실행.
    • 쓰레드가 병렬로 실행되므로 출력 순서는 불규칙할 수 있음.

3.4 생성된 쓰레드 종료 대기

    for (thread& t : threads)
    {
        t.join(); // 각 쓰레드의 종료를 기다림
    }
  • join:
    • 쓰레드가 실행을 완료할 때까지 메인 쓰레드가 대기.
    • 반복문을 통해 모든 쓰레드의 종료를 확인.
    • 주의: join()하지 않으면, 프로그램 종료 시 쓰레드가 제대로 정리되지 않아 비정상 종료될 수 있음.

3.5 주석 처리된 코드

    /* if (t.joinable()) {
           t.join();
       } */
  • joinable():
    • 쓰레드가 유효한 상태인지 확인.
    • 이미 종료되었거나 실행되지 않은 쓰레드를 다시 join하면 런타임 오류 발생 가능.

3.6 무한 루프

    while (true)
    {
    }
  • 의도:
    • 프로그램이 종료되지 않도록 유지.
    • 실제 사용 사례에서는 비효율적이며, GUI 프로그램 등에서 이벤트 루프와 같은 방식으로 대체.

4. 실행 결과 및 흐름

4.1 실행 흐름

  1. 메인 쓰레드에서 10개의 쓰레드를 생성.
  2. 각 쓰레드는 HelloThread를 호출하며 고유한 i 값을 출력.
  3. 메인 쓰레드는 "Hello Main!"을 출력.
  4. 모든 쓰레드의 종료를 join으로 대기.
  5. 프로그램이 종료되지 않도록 while(true)로 유지.

4.2 출력 예시

Hello Main!
Hello Thread 0
Hello Thread 1
Hello Thread 2
Hello Thread 3
Hello Thread 4
Hello Thread 5
Hello Thread 6
Hello Thread 7
Hello Thread 8
Hello Thread 9
  • 출력 순서는 쓰레드의 실행 타이밍에 따라 달라질 수 있음.

5. 멀티스레드 실습: 추가적인 고려 사항

5.1 코어 수와 스레드 수

  • CPU 코어 수:

    • CPU의 코어 수가 쓰레드 실행에 큰 영향을 미침.
    • 예: 4코어 CPU에서 10개의 쓰레드를 생성하면, 4개의 쓰레드가 동시에 실행되고 나머지는 대기.
  • 쓰레드 스케줄링:

    • CPU는 컨텍스트 스위칭을 통해 쓰레드 실행을 전환.
    • 컨텍스트 스위칭이 잦아지면 오버헤드로 인해 성능 저하 발생.

5.2 동기화와 공유 메모리

  • 공유 메모리 문제:

    • 힙과 데이터 영역은 모든 쓰레드가 공유.
    • 스레드 간 데이터 충돌이나 Race Condition 발생 가능.
  • 해결 방법:

    • 뮤텍스(Mutex): 공유 자원 접근을 상호 배타적으로 제어.
    • 세마포어(Semaphore): 특정 자원에 접근할 수 있는 스레드 수 제한.

6. 멀티스레드 프로그램 설계 시 주의점

  1. 적정 스레드 수:

    • CPU 코어 수에 맞는 스레드 수를 생성.
    • 불필요하게 많은 스레드는 컨텍스트 스위칭 비용만 증가.
  2. 자원 동기화:

    • 공유 데이터에 접근할 때는 반드시 동기화 도구 사용.
    • 예: 뮤텍스, 세마포어.
  3. 디버깅 어려움:

    • 스레드는 비동기적으로 실행되므로 디버깅이 복잡.
    • 스레드 동작을 재현하기 어려운 경우가 많음.

profile
李家네_공부방

0개의 댓글