>>[C++ 관련 모든 글 보기]
개요
thread로 부터 수행 결과 값을 받는 방법을 알아 보겠습니다.
기본 원리
future와 thread간 promise를 매개변수로 사용하여 비동기 처리에대한 값을 얻어 옵니다.
1. future
미래에 어떤 값을 받고 자 할 따 사용.
2. promise
future에 값을 넘겨주기 위해서 사용
Code
#include <iostream>
#include <thread>
#include <future>
void worker(std::promise<std::string> *p)
{
p->set_value("some data");
}
int main()
{
std::promise<std::string> p;
std::future<std::string> data = p.get_future();
std::thread t(worker, &p);
// 없어도 아래 get에서 대기 합니다.
data.wait();
std::cout << "받은 데이터 : " << data.get() << std::endl;
t.join();
return 0;
}
무한 대기 회피 (wait_for)
future에서 wait를 하면 무한 대기가 걸립니다. 이를 회피 하는 방법
future에서 제공하는 wait_for를 사용하여 무한 대기를 회피 합니다.
Code
#include <iostream>
#include <thread>
#include <future>
void worker(std::promise<std::string> *p)
{
std::this_thread::sleep_for(std::chrono::seconds(3));
p->set_value("some data");
}
int main()
{
std::promise<std::string> p;
std::future<std::string> data = p.get_future();
std::thread t(worker, &p);
#if 0
/*
* 기본 코드, 무한 대기
*/
data.wait();
#else
while (true) {
std::future_status status = data.wait_for(std::chrono::seconds(1));
if (std::future_status::timeout == status) {
//timeout이 경우 수행
std::cerr << ">";
} else if (std::future_status::ready == status) {
//data에 값이 세팅되었을 경우 수행
break;
}
}
#endif
std::cout << "받은 데이터 : " << data.get() << std::endl;
t.join();
return 0;
}
유의 사항.
std::future에서 get은 딱 1번 밖에사용을 못합니다. 아래와 같이 2번 사용할경우
"error : std::future_error: No associated state" 가 발생 합니다.
std::cout << "받은 데이터 : " << data.get() << std::endl;
try {
std::cout << "받은 데이터 : " << data.get() << std::endl;
} catch (std::exception &e) {
std::cout << "error : " << e.what() << std::endl;
}
std::shared_future 란?
std::shared_future에서 get을 여러번 사용이 필요 할때 사용 합니다.
Ex) 여러 Thread를 동시에 실행 시키고 싶을때 사용 가능 합니다.
각 Thread에서 future::get()를 통하여 대기 하게 한 후, main thread에서 promise를 setting하는 방식으로 사용 합니다.
std::async 란?
thread를 만들어서 관리하고 싶지 않을때 사용 합니다.
앞서 promise 나 packaged_task 는 비동기적으로 실행을 하기 위해서는, 쓰레드를 명시적으로 생성해서 실행해야만 했습니다. 하지만 std::async 에 어떤 함수를 전달한다면, 아예 쓰레드를 알아서 만들어서 해당 함수를 비동기적으로 실행하고, 그 결과값을 future 에 전달합니다.
std::async는 std::task 클래스 기반으로 만들어진 클래스로 Thread를 만들 때 사용됩니다.
std::async는 std::thread와 달리 내부적으로 Thread Pool을 만들어 Thread를 관리하게 되며,
예외처리, 값 return 등.... std::thread보다 안정적이며 프로그래머가 사용하기 편리한 기능입니다.
std::async는 반환 값을 std::future로 받습니다.
Code -1
핵심 코드
std::async(std::launch::async, ()[] {})에서 std::launch::async는 바로 실행하는 선언입니다.
즉, std::async가 a로 넘어가는 순간 바로 실행됩니다.
반면 std::async(std::launch::deferred, ()[] {})에서 std::launch::deferred는 실행하지 않고 대기합니다.
그 후 .get() or .wait()을 만나면 실행하게 됩니다.
이 외에도 std::launch부분을 생략할 수도 있습니다.
#include <iostream>
#include <thread>
#include <future>
int main()
{
std::shared_future<std::string> data = std::async(std::launch::async,[](){
std::this_thread::sleep_for(std::chrono::seconds(3));
return std::string("some data");
});
while (true) {
std::future_status status = data.wait_for(std::chrono::seconds(1));
if (std::future_status::timeout == status) {
//timeout이 경우 수행
std::cerr << ">";
} else if (std::future_status::ready == status) {
//data에 값이 세팅되었을 경우 수행
break;
}
}
std::cout << "받은 데이터 : " << data.get() << std::endl;
try {
std::cout << "받은 데이터 : " << data.get() << std::endl;
} catch (std::exception &e) {
std::cout << "error : " << e.what() << std::endl;
}
return 0;
}
Code - 2
std::future<void> f_thread = std::async(std::launch::async, lambda ())?
get하면 어떻게 되는가?
'ProgrammingLang > c++' 카테고리의 다른 글
[C++개발자되기] 32. STL Container 실무 (0) | 2022.12.28 |
---|---|
[C++개발자되기] 31. sscanf 정규 표현식 (1) | 2022.10.25 |
[C++]Template (0) | 2022.06.21 |
[C++] The Best Parts of C++ (0) | 2022.03.08 |
[C++] 언어의 철학 (0) | 2022.01.25 |