프로그래밍/C++

C++ thread와 async의 차이점

Hwan2 2020. 6. 9. 15:47
반응형

C++에서 병렬처리를 하기위해 여러가지 클래스를 제공합니다.

 

C++에선 std::thread, std::future, std::async를 제공합니다.

 

그 중 많이 쓰이는 std::threadstd::async에 대해 설명해볼까 합니다.

 

 

1. C++에서 Thread와 Async는 다른녀석인가?

 

둘다 같은 쓰레드입니다. 많이 햇갈리는게 Thread라는 개념이 있고, 각 언어별로 Thread를 사용하기위해

프로그래밍 내에 정의된 함수 혹은 객체를 불러옵니다.

 

해당 Thread를 불러오는 방법은 여러가지일 수 있습니다. JAVA의 interface인 run, 클래스 Thread, C언어의 pthread, C++의 thread, async, task 등....

 

전부 다 Thread입니다. 특별한게 없습니다. 

 

단!! 각 클래스별로 내부의 구현이 다르고, 어떤 클래스는 내부에 Thread를 관리할 수 있도록 설계되어 있고, 어떤것은 날 것인 형태도 있고 다양합니다.

 

 

 

 

2. C++에서 Thread와 Async의 차이점

이 둘의 차이점은 내부에 있습니다.

 

std::thread 클래스는 말 그대로 Thread만 생성해주는 역할을 합니다.

 

물론 Thread가 종료를 기다리는 .join() 함수같은 기본적인 함수들을 제공하지만 

 

다시말해서 std::thread는 스레드를 직접 관리할 수 있는 기본적인 방법입니다.

 

 

 

std::async는 C++ 표준 라이브러리의 일부로, 비동기적으로 작업을 실행하고 결과를 std::future 객체를 통해 반환합니다.

 

std::async는 비동기적으로 함수를 실행하고, 실행 결과를 std::future 객체를 통해 제공합니다. 이는 함수의 실행이 완료될 때까지 기다리지 않고, 결과가 준비되면 결과를 얻을 수 있게 해 줍니다.

 

std::async를 사용하면, 비동기 작업 중에 발생한 예외를 std::future 객체를 통해 처리할 수 있습니다. std::future::get() 함수를 호출할 때, 비동기 작업에서 발생한 예외가 재발생하여 예외 처리가 가능합니다.

 

std::async는 함수의 반환 값을 std::future 객체를 통해 제공합니다. 이를 통해 비동기 작업의 결과를 얻을 수 있습니다.

 

3. Thread와 async차이 확인

 

std::thread Class

#include <iostream>
#include <vector>
#include <thread>
#include <cstdio>

void for_print(int num) {
  for (int i = 0; i < 100; i++)
    printf("%d번 Thread : %d\n",num, i);
}

int main(){
  std::vector<std::thread> v_thread;
  v_thread.reserve(2000);

  for (size_t i = 0; i < 2000; i++)
    v_thread.emplace_back(std::thread(for_print, i));

  //join()
  for (size_t i = 0; i < 2000; i++)
    v_thread[i].join();

  std::vector<std::thread>().swap(v_thread);
  return 0;
}

 

 

실행결과

 

 

프로그램이 중간에 멈춰버립니다.

 

마지막 문장을 보면 (코드 : 3개) 라고 되어있는데 정상작동을 하면 (코드 : 0개)로 나와야 합니다.

 

그 다음은std::async를 보겠습니다.

 

 

 

std::async class

#include <iostream>
#include <vector>
#include <future>
#include <cstdio>

void for_print(int num) {
  for (int i = 0; i < 100; i++)
    printf("%d번 Thread : %d\n", num, i);
}

int main() {
  std::vector<std::future<void>> v_async;
  v_async.reserve(2000);

  for (size_t i = 0; i < 2000; i++)
    v_async.emplace_back(std::async(std::launch::async, for_print, i));

  for (size_t i = 0; i < 2000; i++)
    v_async[i].wait();

  return 0;
}

 

 

실행결과

 

마지막 문장을 보시면 (코드 : 0개)를 확인할 수 있습니다.

 

 

물론 이건 실험을 하려고 Thread를 2000개 만들었지만, 이렇게 많이 만들 수도 없습니다.

 

운영체제에서 프로세스에 할당되는 Thread의 갯수를 재한하고 있기 떄문입니다.

물론 Thread를 2000개 만들 수 있다고 해도 엄청난 context switching과 메모리를 많이 먹어 비효율적으로 될 것입니다.

 

본론으로 돌아와서 위 실행 결과에서 알 수 있듯이 std::async는 내부적으로 Thread를 관리하여 사용자가 2000개를 입력해도

 

내부적으로 Thread의 갯수를 정해, 각 쓰래드마다 작업(task)을 할당해 주게 됩니다.

 

 

 

그래서 일반적으로 Thread를 사용하게 된다면 std::async를 권장합니다.

 

하지만 Thread를 프로그래머에 맞게 관리를 하고 싶다면 std::thread를 사용하면 되고,

 

직접 Thread Pool를 만들어서 관리하면 됩니다.

 

 

 

 

 

 

 

 

반응형