수색…
소개
Promises and Futures는 하나의 객체를 하나의 스레드에서 다른 스레드로 페리하는 데 사용됩니다.
std::promise
객체는 결과를 생성하는 쓰레드에 의해 설정된다.
std::future
객체를 사용하여 값을 검색하거나 값을 사용할 수 있는지 테스트하거나 값을 사용할 수있을 때까지 실행을 중지 할 수 있습니다.
std :: future와 std :: promise
다음 예제는 다른 스레드가 사용할 약속을 설정합니다.
{
auto promise = std::promise<std::string>();
auto producer = std::thread([&]
{
promise.set_value("Hello World");
});
auto future = promise.get_future();
auto consumer = std::thread([&]
{
std::cout << future.get();
});
producer.join();
consumer.join();
}
연기 된 비동기 예제
이 코드는 std::async
버전을 구현하지만 deferred
실행 정책으로 항상 async
가 호출 된 것처럼 동작합니다. 이 함수는 또한 async
의 특별한 future
행동을 갖지 않습니다. 반환 된 future
는 가치를 획득하지 않고 파괴 future
수 있습니다.
template<typename F>
auto async_deferred(F&& func) -> std::future<decltype(func())>
{
using result_type = decltype(func());
auto promise = std::promise<result_type>();
auto future = promise.get_future();
std::thread(std::bind([=](std::promise<result_type>& promise)
{
try
{
promise.set_value(func());
// Note: Will not work with std::promise<void>. Needs some meta-template programming which is out of scope for this example.
}
catch(...)
{
promise.set_exception(std::current_exception());
}
}, std::move(promise))).detach();
return future;
}
std :: packaged_task 및 std :: future
std::packaged_task
는 반환 유형에 대한 함수와 관련 약속을 묶습니다.
template<typename F>
auto async_deferred(F&& func) -> std::future<decltype(func())>
{
auto task = std::packaged_task<decltype(func())()>(std::forward<F>(func));
auto future = task.get_future();
std::thread(std::move(task)).detach();
return std::move(future);
}
스레드가 즉시 실행되기 시작합니다. 분리하거나 범위 끝 부분에 결합 할 수 있습니다. std :: thread에 대한 함수 호출이 끝나면 결과가 준비됩니다.
이 약간 다릅니다 std::async
반환 된 경우 std::future
스레드가 완료 될 때까지 파괴 실제로 차단합니다.
std :: future_error 및 std :: future_errc
std :: promise 및 std :: future의 제약이 채워지지 않은 경우 std :: future_error 유형의 예외가 발생합니다.
예외의 오류 코드 구성원은 std :: future_errc 유형이며 값은 일부 테스트 사례와 함께 다음과 같습니다.
enum class future_errc {
broken_promise = /* the task is no longer shared */,
future_already_retrieved = /* the answer was already retrieved */,
promise_already_satisfied = /* the answer was stored already */,
no_state = /* access to a promise in non-shared state */
};
비활성 약속 :
int test()
{
std::promise<int> pr;
return 0; // returns ok
}
약속 된 미사용 :
int test()
{
std::promise<int> pr;
auto fut = pr.get_future(); //blocks indefinitely!
return 0;
}
이중 검색 :
int test()
{
std::promise<int> pr;
auto fut1 = pr.get_future();
try{
auto fut2 = pr.get_future(); // second attempt to get future
return 0;
}
catch(const std::future_error& e)
{
cout << e.what() << endl; // Error: "The future has already been retrieved from the promise or packaged_task."
return -1;
}
return fut2.get();
}
std :: promise 값을 두 번 설정 :
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
try{
std::promise<int> pr2(std::move(pr));
pr2.set_value(10);
pr2.set_value(10); // second attempt to set promise throws exception
}
catch(const std::future_error& e)
{
cout << e.what() << endl; // Error: "The state of the promise has already been set."
return -1;
}
return fut.get();
}
std :: future와 std :: async
다음 순진 병합 정렬 예에서 std::async
는 여러 병렬 병합 작업을 시작하는 데 사용됩니다. std::future
는 결과를 기다리고 동기화합니다.
#include <iostream>
using namespace std;
void merge(int low,int mid,int high, vector<int>&num)
{
vector<int> copy(num.size());
int h,i,j,k;
h=low;
i=low;
j=mid+1;
while((h<=mid)&&(j<=high))
{
if(num[h]<=num[j])
{
copy[i]=num[h];
h++;
}
else
{
copy[i]=num[j];
j++;
}
i++;
}
if(h>mid)
{
for(k=j;k<=high;k++)
{
copy[i]=num[k];
i++;
}
}
else
{
for(k=h;k<=mid;k++)
{
copy[i]=num[k];
i++;
}
}
for(k=low;k<=high;k++)
swap(num[k],copy[k]);
}
void merge_sort(int low,int high,vector<int>& num)
{
int mid;
if(low<high)
{
mid = low + (high-low)/2;
auto future1 = std::async(std::launch::deferred,[&]()
{
merge_sort(low,mid,num);
});
auto future2 = std::async(std::launch::deferred, [&]()
{
merge_sort(mid+1,high,num) ;
});
future1.get();
future2.get();
merge(low,mid,high,num);
}
}
주 : 예에서 std::async
는 policy std::launch_deferred
시작됩니다. 이는 모든 호출에서 새 스레드가 작성되지 않도록하기위한 것입니다. 우리 예제의 경우, std::async
대한 호출은 순서가 맞지 않아 std::future::get()
에 대한 호출에서 동기화됩니다.
std::launch_async
는 모든 호출에서 새 스레드를 작성하도록합니다.
기본 정책은 std::launch::deferred| std::launch::async
는 구현이 새로운 쓰레드 생성을위한 정책을 결정한다는 것을 의미한다.
비동기 작업 클래스
- std :: async : 비동기 작업을 수행합니다.
- std :: future : 비동기 작업 결과에 대한 액세스를 제공합니다.
- std :: promise : 비동기 작업의 결과를 패키징합니다.
- std :: packaged_task : 반환 형식에 대해 함수와 관련 약속을 묶습니다.