C++ 쓰레드(thread)

은수·2022년 7월 4일

cpp study

목록 보기
18/21

멀티 쓰레드 프로그램

프로세스

  • 운영체제에서 실행되는 프로그램의 최소 단위. 보통 1개의 프로그램을 가리킬 때 1개의 프로세스를 의미하는 경우가 많음.
  • CPU의 코어에서 실행됨.

컨텍스트 스위칭 (Context switching)

  • CPU가 한 프로그램을 통째로 쭉 실행시키는 것이 아니라, 이 프로그램 조금, 저 프로그램 조금씩 골라서 차례를 돌며 실행시키는 것을 의미
  • 이 때, CPU는 운영체제의 스케쥴러(scheduler) 를 통해, 어느 프로그램으로 스위치할지 결정받음

쓰레드 (thread)

  • CPU 코어에서 돌아가는 프로그램 단위
  • 즉, CPU 코어 하나에 한번에 한 개의 쓰레드의 명령을 실행
  • 1개의 프로세스는 최소 한 개에서 여러 개의 쓰레드로 이루어짐

멀티 쓰레드(multithread) 프로그램 : 여러개의 쓰레드로 구성된 프로그램

쓰레드와 프로세스 차이점

프로세스들은 서로 메모리를 공유하지 않음.

  • 프로세스 1과 프로세스 2는 서로의 메모리에 접근 불가.

같은 프로세스 내 쓰레드끼리는 메모리를 공유함.

  • 한 프로세스 내에 쓰레드 1, 쓰레드 2가 있다면 서로 같은 메모리를 공유함.

왜 멀티쓰레드인가 ?

병렬 가능한 작업들

  • 어떠한 작업을 여러개의 다른 쓰레드를 이용해서 좀 더 빠르게 수행할 수 있음.

프로그램 논리 구조 상에서,
연산들 간의 의존 관계가 많을 수 록 병렬화가 어려워지고,
반대로 다른 연산의 결과와 관계없이 독립적으로 수행할 수 있는 구조가 많을 수 록 병렬화가 매우 쉬워짐!

대기시간이 긴 작업들

웹사이트를 다운받는 것과 같이 대기시간이 긴 작업을 수행할 때, 여러 개의 쓰레드를 사용하면 더 효율적으로 작업할 수 있음.


C++에서 쓰레드 생성하기

c++ 11부터 표준에 thread가 추가됨.

// 내 생에 첫 쓰레드
#include <iostream>
#include <thread>
using std::thread;

void func1() {
  for (int i = 0; i < 10; i++) {
    std::cout << "쓰레드 1 작동중! \n";
  }
}

void func2() {
  for (int i = 0; i < 10; i++) {
    std::cout << "쓰레드 2 작동중! \n";
  }
}

void func3() {
  for (int i = 0; i < 10; i++) {
    std::cout << "쓰레드 3 작동중! \n";
  }
}
int main() {
  thread t1(func1);
  thread t2(func2);
  thread t3(func3);

  t1.join();
  t2.join();
  t3.join();
}
  • func1, func2, func3이 각기 다른 thread 상에서 실행됨.
  • 이 때 중요한 점은, 이 쓰레드들이 CPU코어에 어떻게 할당되고, 또 언제 컨텍스트 스위치를 할 지는 운영체제의 마음에 달려있다는 점!

--> 운영체제가 쓰레드들을 어떤 코어에 할당하고, 또 어떤 순서로 스케쥴 할지는 그 때 그 때 마다 상황에 맞게 바뀌기 때문에 결과 예측이 불가하며, 매번 결과가 달라짐.

join과 detach

t1.join();
t2.join();
t3.join();

or 

t1.detach();
t2.detach();
t3.detach();

join 함수

  • 해당하는 쓰레드들이 실행을 종료하면 리턴하는 함수.
  • 따라서, t1.join()의 경우 t1이 종료하기 전까지 리턴하지 않음.

detach 함수

  • 해당 쓰레드를 실행 시킨 후, 잊어버리는 것
  • 대신 쓰레드는 알아서 백그라운드에서 돌아가게 됨.

join 되거나 detach 되지 않는 쓰레드들의 소멸자가 호출된다면 예외를 발생시키도록 명시되어 있음.


쓰레드에 인자 전달하기

쓰레드는 리턴값 이란것이 없기 때문에 만일 어떠한 결과를 반환하고 싶다면 포인터의 형태로 전달하면 됨.

쓰레드를 생성할 때 함수에 인자들을 전달하는 방법은 이전에 std::bind 를 사용했던 방법과 유사

thread(worker, data.begin() + i * 2500, data.begin() + (i + 1) * 2500,
       &partial_sums[i])

thread 생성자의 첫번째 인자로 함수를 전달하고, 이어서 해당 함수에 전달할 인자를 나열

0개의 댓글