1. std::async에 대한 간단한 설명.
std::async
는 std::task
클래스 기반으로 만들어진 클래스로 Thread를 만들 때 사용됩니다.
std::async
는 std::thread
와 달리 내부적으로 Thread Pool을 만들어 Thread를 관리하게 되며,
예외처리, 값 return 등.... std::thread
보다 안정적이며 프로그래머가 사용하기 편리한 기능입니다.
std::async
는 반환 값을 std::future
로 받습니다.
2. std::async constructor
#include <iostream>
#include <future>
void for_print(char c) {
for (int i = 0; i < 100; i++)
printf("%c번 Thread : %d\n", c, i);
}
int main() {
std::future<void> a = std::async(std::launch::async, for_print, 'a');
std::future<void> b = std::async(std::launch::deferred, for_print, 'b');
std::future<void> c = std::async(for_print, 'c');
b.get();
return 0;
}
std::async(std::launch::async, for_print, 'a')
에서 std::launch::async
는 바로 실행하는 선언입니다.
즉, std::async
가 a로 넘어가는 순간 바로 실행됩니다.
반면 std::async(std::launch::deferred, for_print, 'b')
에서 std::launch::deferred
는 실행하지 않고 대기합니다.
그 후 .get() or .wait()
을 만나면 실행하게 됩니다.
이 외에도 std::launch
부분을 생략할 수도 있습니다.
3. std::future_error
#include <iostream>
#include <future>
void for_print(char c) {
for (int i = 0; i < 10; i++)
printf("%c번 Thread : %d\n", c, i);
//return 1;
}
int main() {
auto c = std::async(for_print, 'c');
std::future<int> d;
try {
c.get();
d.get();
}
catch (const std::future_error& e) {
std::cout << "Caught a future_error with code \"" << e.code()
<< "\"\nMessage: \"" << e.what() << "\"\n";
}
return 0;
}
실행결과
정의되지 않은 future에 대해서 .get()
호출 시 예외를 처리해주는 코드입니다. .wait()
을 해도 동일한 결과값을 얻어낼 수 있습니다.
4. std::future.wait_for()
#include <iostream>
#include <future>
#include <chrono>
const int number = 444444443;
// a non-optimized way of checking for prime numbers:
bool is_prime(int x) {
for (int i = 2; i < x; ++i) if (x % i == 0) return false;
return true;
}
int main()
{
// call function asynchronously:
std::future<bool> fut = std::async(is_prime, number);
// do something while waiting for function to set future:
std::cout << "checking, please wait";
std::chrono::milliseconds span(100);
//std::chrono::duration<int> span (1);
while (fut.wait_for(span) != std::future_status::ready) { // == std::future_status::timeout
std::cout << '.';
std::cout.flush();
}
bool x = fut.get(); // retrieve return value
std::cout << "\n" << number << " " << (x ? "is" : "is not") << " prime.\n";
return 0;
}
실행결과
.wait_for()
는 해당 Thread가 끝날때까지의 상태를 반환해줍니다.
인자 값으로는 std::chrono::
클래스의 객체를 받습니다.
시간을 지정해주고 해당 시간이 지남에 따라 Thread의 상태가 어떤지 알려주게 됩니다.
5. std::async를 이용한 parallelsum
#include <iostream>
#include <future>
#include <algorithm>
template <typename it>
int parallel_sum(it start, it end) {
int len = end - start;
if (len <= 1)
return 0;
it newStart = start + 200;
auto hendle = std::async(parallel_sum<it>, newStart, end);
int sum = 0;
for_each(start, newStart, [&](int n) { sum += n; /* std::cout << n << "\n"; */ });
return sum + hendle.get();
}
int main()
{
std::vector<int> v;
v.reserve(1001);
for (int i = 1; i < 1001; i++) v.emplace_back(i);
std::cout << "sum : " << parallel_sum(v.begin(), v.end()) << "\n";
return 0;
}
실행 결과
1 ~ 1000 까지의 합을 Thread 5개를 생성해 병렬로 계산한 코드입니다.
1 ~ 200.
201 ~ 400.
401 ~ 600.
601 ~ 800.
801 ~ 1000
이렇게 말이죠.
여기서 주목해야할 점은 hendle.get()
함수를 통해 합을 정확하게 계산한 점입니다.
std::thread
로 해당 코드를 구현한다면 상당히 복잡해질 것입니다.
끝.