https://donot-simsim.tistory.com/35
여기서 이어지는 두 번째.
2. std::thread는 해당 함수를 통해 값을 가져오는 건 좀 귀찮아서, 주로 watchdog 같은 곳에 사용하게 되더라.
반면 std::async는 만드는 순간 future object를 되돌려주기 때문에, 해당 함수에서 값을 얻어오는 대에 특화되어있다.
이번엔 두 번쨰.
async 는 thread와는 달리,만들 때 future object를 받는다.
그리고 그 future object를 통하여 값을 받아올 수 있다.
#include <future>
#include <iostream>
unsigned int func() {
std::this_thread::sleep_for(std::chrono::seconds(2));
return 3;
}
int main() {
std::cout << "main start" << std::endl;
std::future<unsigned int> t1 = std::async(func);
std::cout << t1.get() << std::endl;
std::cout << "main end" << std::endl;
return 0;
}
이런 식으로.
이 함수를 수행하고 있으렴. 그럼 나중에 와서 값을 가져갈게~
이런 개념으로 사용하게 되었다.
그래서 실제로 사용을 해 보면
#include <future>
#include <iostream>
unsigned int func(int st, int ed) {
int res = 0;
for (int i = st; i < ed; i++) {
res += i;
}
return res;
}
int main() {
std::cout << "main start" << std::endl;
std::future<unsigned int> t1 = std::async(func, 1, 50001);
std::future<unsigned int> t2 = std::async(func, 50003, 88190);
std::cout << t1.get() + t2.get() << std::endl;
std::cout << "main end" << std::endl;
return 0;
}
이런 식으로, 오래 걸리는 일을 시켜두고, 값만 가져간다는 느낌으로 사용하게 되었다.
반면, thread를 통해 위의 코드를 나타낸다고 하면..
#include <iostream>
std::atomic<unsigned int> res{ 0 };
void func(int st, int ed) {
int res = 0;
for (int i = st; i < ed; i++) {
res += i;
}
::res += res;
}
int main() {
std::chrono::high_resolution_clock clock;
auto starttime = clock.now();
std::cout << "main start" << std::endl;
auto t1 = std::thread(func, 1, 50001);
auto t2 = std::thread(func, 50003, 88190);
std::this_thread::sleep_for(std::chrono::seconds(2));
if (t1.joinable()) t1.join();
if (t2.joinable()) t2.join();
std::cout << ::res << std::endl;
std::cout << "main end" << std::endl;
return 0;
}
이런 느낌이 되려나...
여튼 return값이 없으니 굉장히 귀찮아진다. 애초에 이런 식으로 쓰기 위해 만든 놈이 아닌 듯 하다.
다만 watchdog처럼 계속 무언가의 상태를 보아야 한다면..
#include <future>
#include <iostream>
std::atomic<int> num{0};
std::atomic<bool> stopFlag{ false };
void func(int st, int ed) {
while (stopFlag == false) {
if (st < num && num < ed) {
std::cout << "between!" << std::endl;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main() {
std::cout << "main start" << std::endl;
{
std::thread(func, 1, 10).detach();
auto a1 = std::async(func, 11, 20);
}
while (true) {
int tmp;
std::cin >> tmp;
if (tmp == 0) {
stopFlag = true;
break;
}
num = tmp;
}
std::cout << "main end" << std::endl;
return 0;
}
위의 코드가 있다.
func는 num이 특정 수 boundary 안에 들어오는지 확인하고, between을 출력한다.
{
std::thread(func, 1, 10).detach();
auto a1 = std::async(func, 11, 20);
}
이 부분은 {} 을 만들어서, 생성 / 소멸의 과정을 거치게끔 만든 것이다.
먼저 thread만 살리고 async를 주석해서 돌려보면
이런 식으로, 매우 잘 돈다.
생성자든 소멸자든, 이미 detach로 분리시켜 버렸기 때문에 알아서 돌다가, 끝날떄 flag만 제대로 넘겨주면 잘 종료된다.
하지만 thread를 주석처리 하고, async를 돌리면?
죽는다.
future object가 소멸될 때, 관련된 함수가 끝날 때까지 기다렸다가 값을 받아가기 때문이라고 말한다.
위 코드에서는, {} 를 나갈 때 future가 소멸된다.
그러므로 a1은 실행시킨 func이 끝나기까지 기다리지만, 내부에서는 StopFlag를 기다리며 무한 루프를 돌게 되므로 위와 같은 상황이 벌어지게 된다.
c++ - Is there a way to cancel/detach a future in C++11? - Stack Overflow
위 부분을 class 내부에서 돌린다면... 해당 future object를 class member 변수로 가지고 있게 해서, 그 class가 소멸될 때까지 잘 관리를 해 주면 되겠지만, 굳이? 라는 생각이 더 크게 들더라.
thread는 만들고 그냥 detach 해 버리면 되는데...
그래서 결국
thread -> watchdog
async -> 오래 걸리는 일을 비동기적으로 작업해 return을 얻어올 때
이런 식으로 사용하게 되었다.
* 잘못된 정보는 알려주시면 너무너무 감사합니다.
'C++ > STL' 카테고리의 다른 글
[C++20] Concepts (1) | 2023.05.23 |
---|---|
[C++] std::async. launch policy (0) | 2023.04.20 |
[C++] std::async, std::thread (1) (0) | 2023.04.09 |
[C++17] std::filesystem::path (0) | 2023.04.04 |
[C++17 ] FOLD Expression (0) | 2023.03.29 |