C++的future,promise,packaged_task

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();
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章