close

今天來記錄個覺得應該很有用的東西

就是promise,future和async

以下是幾個我參考的網頁:

https://wizardforcel.gitbooks.io/cpp-11-faq/content/70.html

https://www.justsoftwaresolutions.co.uk/threading/multithreading-in-c++0x-part-8-futures-and-promises.html

https://kheresy.wordpress.com/2016/03/14/async-and-future-in-c11/

 

先從future和promise開始看起好了

future從字面看是未來的意思,也就是代表:現在沒辦法馬上獲得結果,也許之後才會得到結果

promise字面上是承諾的意思,也就是會給予一個值

以下來看一個簡單的範例:

void print_int(std::future<int>& fut) {
    int x = fut.get(); // 获取共享状态的值.
    std::cout << "value: " << x << '\n'; // 打印 value: 10.
}

int main ()
{
    std::promise<int> prom; // 生成一个 std::promise<int> 对象.
    std::future<int> fut = prom.get_future(); // 和 future 关联.
    std::thread t(print_int, std::ref(fut)); // 将 future 交给另外一个线程t.
    prom.set_value(10); // 设置共享状态的值, 此处和线程t保持同步.
    t.join();
    return 0;
}

其實裡面註解就解釋得很清楚了

我們可以綁定future到promise裡面,然後把future設定到另一個thread中

當main thread需要傳送資料給child thread時,可以用promise去設定那個值

而在child thread裡面可以用future去get那個值

進而達到multithread間溝通和同步的效果

 

其實從上面的例子看起來,future有點像是thread之間shared的狀態

而promise就是設定那個狀態的一個接口

 

所以說我們如果要實作一個可以從外部中斷的task,我們就可以利用這個機制來實作

比如說在一個物件裡面,包含一個promise和一個future:

class Stoppable
{
    std::promise<void> exitSignal;
    std::future<void> futureObj;

public:
    Stoppable() : futureObj(exitSignal.get_future()) 
    {
        std::cout << "Initialize Stoppable task" << std::endl;
    }

    virtual ~Stoppable()
    {
        std::cout << "disconstruct the task" << std::endl;
    }

    Stoppable(Stoppable && obj) : exitSignal(std::move(obj.exitSignal)), futureObj(std::move(obj.futureObj))
    {
        std::cout << "Move Constructor is called" << std::endl;
    }

    Stoppable & operator=(Stoppable && obj)
    {
        std::cout << "Move Assignment is called" << std::endl;
        exitSignal = std::move(obj.exitSignal);
        futureObj = std::move(obj.futureObj);
        return *this;
    }

    void operator()()
    {
        run();
    }

    // check if this task is requested to stop. 
    bool stopRequested()
    {
        while (futureObj.wait_for(std::chrono::milliseconds(0)) == std::future_status::timeout)
        {
            // futureObj has not received stop signal, so this task is not requested to stop.
            return false;
        }
        return true;
    }

    // request this task to stop by setting value to promise.
    void stop()
    {
        exitSignal.set_value();
    }

private:
    virtual void run() = 0;
};

當呼叫stop()的時候便會去設定promise的值,在run()的實作中就可以去檢查future的值,利用這個特性去達到停止的效果,比如說像這樣:

void counter::run()
{
    int count = 0;

    while (stopRequested() == false)
    {
        std::cout << "count = " << count << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        ++count;
    }

    std::cout << "counter end" << std::endl;
}

上面是一個counter實作的例子,這個counter會一直數到使用者呼叫stop()為止

如果簡單執行的話,就是開一個thread來執行:

counter c();
std::thread th([&]() {
    c.run();
});

當然也可以在counter裡面有一個thread的member然後用這個thread來執行,

抑或是在Stoppable裡面就有一個thread的member來讓子類繼承,我想都是可以的

 

async的話使用上就比較單純,如果是簡單使用的話建議用async就行了

和future結合使用也很方便,以下是一個範例:

int Compute( int iIn)
{
    std::this_thread::sleep_for(std::chrono::seconds(iIn));
    return iIn;
}

int main(int argcchar** argv)
{
    auto tpStart = std::chrono::high_resolution_clock::now();

    std::future<int> fuRes1 = std::async(std::launch::async, Compute, 1),
        fuRes2 = std::async(std::launch::async, Compute, 2);

    int iResult = fuRes1.get() + fuRes2.get();
    auto duTime = std::chrono::high_resolution_clock::now()  tpStart;
    
    std::cout << "Result is " << iResult << ", use "
        << std::chrono::duration_cast<std::chrono::milliseconds>(duTime).count()
        << "ms" << std::endl;
}

async的特點就是它會有個回傳值,而可以使用future去接async的回傳值

使用上就用future.get()去得到回傳的值,而如果還沒拿到回傳值的話就會停在那邊等待

以這個例子來說,主程式會卡在iResult那邊,等到兩個值都算完之後可以加起來才會繼續

然後這邊還有計算一下執行的時間,也可以參考一下用法

另外上述做法也可以用thread來實現,大該就是要傳參數進去讓thread可以把值存到參數中,比較麻煩一點

具體的做法可以參考: https://kheresy.wordpress.com/2016/03/14/async-and-future-in-c11/

 

大概就這樣啦,稍微知道一下用法而已

其實這樣就可以便很多花招了XD

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 頁頁頁六滴 的頭像
    頁頁頁六滴

    人森很精彩,所以要把所有事情都記起來=ˇ=

    頁頁頁六滴 發表在 痞客邦 留言(0) 人氣()