일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 참조자
- resource management class
- more effective c++
- 보편 참조
- 영화
- effective modern c++
- 상속
- 언리얼
- iterator
- Smart Pointer
- effective stl
- reference
- operator new
- 영화 리뷰
- exception
- 스마트 포인터
- virtual function
- 게임
- 예외
- Effective c++
- implicit conversion
- UE4
- c++
- 오블완
- 암시적 변환
- 티스토리챌린지
- universal reference
- std::async
- lua
- 반복자
Archives
- Today
- Total
스토리텔링 개발자
[Effective Modern C++] 36. std::async의 시동 방침(launch policy) 본문
Effective C++/Effective Modern C++
[Effective Modern C++] 36. std::async의 시동 방침(launch policy)
김디트 2025. 4. 10. 11:15728x90
항목 36. 비동기성이 필수일 때에는 std::launch::async를 지정하라
std::async 호출
- 함수를 비동기적으로 실행하겠다는 의미
- 하지만 늘 그런 의미일 필요는 없다.
- 함수를 어떤 시동 방침(launch policy)에 따라 실행한다는 의미도 가진다.
표준이 제공하는 시동 방침
- std::launch 라는 enum으로 제공된다.
- std::launch::async
- f는 반드시 비동기적으로(다른 스레드에서) 실행된다.
- std::launch::deferred
- f는 std::async가 리턴한 future 객체에 대해 get이나 wait가 호출될 때까지 실행이 지연된다.
- std::async의 기본 방침은 위 두 가지를 or로 결합한 것이다.
- 결과적으로 기본 방침으로는 함수의 실행이 비동기일수도 동기일수도 있다.
// 아래 둘은 동일하다.
auto fut1 = std::async(f);
auto fut2 = std::async(std::launch::async | std::launch::deferred, f);
std::async를 기본 시동 방침으로 호출한 영향
// 아래 문장이 스레드 t에서 실행된다고 가정한다면
auto fut = std::async(f);
- f가 지연 실행될 수 있으므로 f와 t가 동시에 실행될지 예측하기가 불가능하다.
- f가 fut의 get, wait를 호출하는 스레드와 다른 스레드에서 실행될지 예측하기가 불가능하다.
- get, wait를 호출한다는 보장이 없을 수 있으므로 f가 반드시 실행될 것인지 예측하기가 불가능할 수도 있다.
- thread_local 변수(스레드 지역 변수)를 사용하기 힘들다.
- 스레드 지역 저장소(thread-local storage, TLS)를 읽고 쓰는 코드가 f 내에 있다면
- 그 코드가 어떤 스레드의 지역 변수에 접근할지 예측할 수 없기 때문이다.
- 만료 시간이 있는 wait 기반 루프가 영원히 끝나지 않을 수 있다.
- 지연되었다면, wait_for나 wait_until 호출 시 std::future_status::deffered가 리턴되기 때문이다.
using namespace std::literals;
void f()
{
std::this_thread::sleep_for(ls); // 1초 sleep
}
// f를 비동기 실행
auto fut = std::async(f);
// f의 실행이 끝날 때까지 루프.
// 허나, 안 끝날 수가 있다!!
whild(fut.wait_for(100ms) != std::future_status::ready)
{
...
}
- 해결 방법 : 지연 여부를 확인하여 지연 시 루프에 진입하지 않도록 처리하면 될 것이다.
- 하지만, 안타깝게도 지연 여부를 future 객체로 직접 알아낼 방법이 없다.
- wait_for 같은 시간 만료 기반 함수를 호출할 수밖에 없다.
auto fut = std::async(f);
// 지연 되었는지 체크
if(fut.wait_for(0s) == std::future_status::deffered)
{
// f를 동기로 호출 처리
...
}
else
{
// 지연되지 않았을 시
while(fut.wait_for(100ms != std::future_status::ready)
{
...
}
...
}
기본 시동 방침과 함께 std::async를 사용하려면 지켜야 할 조건
- get, wait를 호출하는 스레드와 반드시 동기적일 필요가 없다.
- 여러 스레드 중 어떤 스레드의 thread_local 변수들을 읽고 쓰는지가 중요하지 않다.
- std::async가 돌려준 future 객체에 get, wait가 반드시 호출된다는 보장이 없어도 된다.
- std::async를 통한 함수가 전혀 실행되지 않아도 된다.
- 함수 실행이 지연된 항태일 수도 있다는 점이 wait_for나 wait_until을 사용하는 코드에 반영되어 있다.
std::async가 반드시 비동기적으로 실행되도록 하는 방법
- launch::async를 첫 인수로 지정한다.
auto = fut = std::async(std::launch::async, f); // f를 비동기 실행
- std::launch::async 시동 방침을 명시적으로 지정하지 않는 함수를 만들어보자.
// C++11 버전
template<typename F, typename... Ts>
inline std::future<typename std::result_of<F(Ts...)>::type> reallyAsync(F&& f, Ts&&... params)
{
return std::async(std::launch::async, std::forward<F>(f), std::forward<Ts>(params)...);
}
// C++14 버전
template<typename F, typename... Ts>
inline auto reallyAsync(F&& f, Ts&&... params)
{
return std::async(std::launch::async, std::forward<F>(f), std::forward<Ts>(params)...);
}
728x90
'Effective C++ > Effective Modern C++' 카테고리의 다른 글
[Effective Modern C++] 38. 스레드 핸들 소멸자의 동작 (0) | 2025.04.15 |
---|---|
[Effective Modern C++] 37. std::thread는 unjoinable하게 (0) | 2025.04.11 |
[Effective Modern C++] 35. 태스크 기반 프로그래밍(task-based programming) (0) | 2025.04.09 |
[Effective Modern C++] 34. std::bind 대신 람다 (0) | 2025.04.08 |
[Effective Modern C++] 33. auto&& 매개변수를 std::forward로 전달할 땐 decltype (0) | 2025.04.04 |
Comments