1. future與async配合使用
個人理解就是用future獲取該線程函數的返回值,並可以知道該線程函數何時執行完;
#include <iostream>
#include <string>
#include <thread>
#include <future>
unsigned long long CalcuBigNum(unsigned long long ullN)
{
std::this_thread::sleep_for(std::chrono::milliseconds(ullN));
std::cout << "hello!" << std::endl;
return std::pow(ullN, 2);
}
struct X
{
void foo(int n, std::string const& str)
{
std::cout << std::to_string(n) + str << "\n";
};
std::string bar(std::string const& str)
{
return str + str;
};
};
struct Y
{
double operator()(double f)
{
return 2 * f;
};
};
class move_only
{
public:
move_only() {};
move_only(move_only&&) {};
move_only(move_only const&) = delete;
move_only& operator=(move_only&&) {};
move_only& operator=(move_only const&) = delete;
void operator()() {};
};
X baz(X& x) { return x; };
int main()
{
X x;
// std::future<unsigned long long> f0
auto f0 = std::async(std::launch::async, CalcuBigNum, 1000); // 這裏的f0 get的是CalcuBigNum的返回值
std::cout << "Hello World!\n" << f0.get() << "\n";
auto f1 = std::async(&X::foo, &x, 42, "hello");
auto f2 = std::async(&X::bar, x, "goodbye"); // 調用tmpx.bar("goodbye"), tmpx是x的拷貝副本
auto f3 = std::async(Y(), 3.141); // 調用tmpy(3.141),tmpy通過Y的移動構造函數得到
Y y;
auto f4 = std::async(std::ref(y), 2.718); // 調用y(2.718)
auto f5 = std::async(move_only()); // 調用tmp(),tmp是通過std::move(move_only())構造得到
auto f6 = std::async(std::launch::async, Y(), 1.2); // 在新線程上執行
auto f7 = std::async(std::launch::deferred, baz, std::ref(x)); // 在wait()或get()調用時執行
auto f8 = std::async(std::launch::deferred | std::launch::async,baz, std::ref(x)); // 實現選擇執行方式
auto f9 = std::async(baz, std::ref(x));
f7.wait(); // 調用延遲函數
int i = 0;
}
2. future與promise配合使用
可以用創建的promise獲取其future,並在線程中或線程結束時設置其值,方便的獲取線程中所需要的值。
配合exception_ptr可以將拋出的異常保存起來,在適當的時候處理並拋出
因此promise更加靈活,可以選擇在線程函數中何時爲future賦值
void get_int(std::promise<int>& prom)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
prom.set_value(666);
//prom.set_value_at_thread_exit(666);
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
void get_exception(std::promise<std::exception_ptr>& prom)
{
std::exception_ptr eptr;
try {
std::string().at(1); // this generates an std::out_of_range
}
catch (...) {
eptr = std::current_exception(); // capture
prom.set_exception(eptr);
//prom.set_exception_at_thread_exit(eptr);
}
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
void handle_exception(std::exception_ptr excep_ptr)
{
try {
if (excep_ptr)
{
std::rethrow_exception(excep_ptr);
}
}
catch (std::exception & ex)
{
std::cout << "Caught exception \"" << ex.what() << "\"\n";
}
}
void testPromise()
{
try
{
std::promise<int> prom;
std::future<int> fut = prom.get_future();
std::thread th1(get_int, std::ref(prom));
th1.detach();
std::cout << fut.get() << "\n";
}
catch (std::exception & ex)
{
std::cout << "Caught exception \"" << ex.what() << "\"\n";
}
try
{
std::promise<std::exception_ptr> prom;
std::future<std::exception_ptr> fut = prom.get_future();
std::thread th1(get_exception, std::ref(prom));
th1.detach();
handle_exception(fut.get());
}
catch (std::exception & ex)
{
std::cout << "Caught exception \"" << ex.what() << "\"\n";
}
}
運行結果如下圖
3. future與packaged_task配合使用
可以將可調用對象包裝在packaged_task實例中,並通過get_future與future實例綁定,並通過future實例獲取可調用對象的執行結果,通過比較packaged_task與promise可以知道,兩者類似,都是一旦有結果future就可以get到,promise爲設置值,packaged_task爲設置的可執行對象返回結果。
unsigned long long CalcuBigNum(unsigned long long ullN)
{
std::this_thread::sleep_for(std::chrono::milliseconds(ullN));
std::cout << "hello!" << std::endl;
return std::pow(ullN, 2);
}
void testPackageTask()
{
std::packaged_task<unsigned long long(unsigned long long)> pkt(CalcuBigNum);
std::future<unsigned long long> fut = pkt.get_future();
unsigned long long ullBigNum = 5000;
std::thread th([&pkt, ullBigNum]() {
pkt(ullBigNum);
//pkt.make_ready_at_thread_exit(0);
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
});
th.detach();
while (std::future_status::ready != fut.wait_for(std::chrono::milliseconds(10)))
{
std::cout << ".";
}
std::cout << "\n" << "the result is:" << fut.get();
}