歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C++並發編程 異步任務

C++並發編程 異步任務

日期:2017/3/1 9:08:33   编辑:Linux編程

C++並發編程 異步任務

異步任務 std::async

(1) std::async 會返回一個 std::future 對象, 這個對象持有最終計算出來的結果. 當需要這個值時, 只需要調用對象的get()成員函數. 並且直到“期望”狀態為就緒的情況下, 線程才會阻塞; 之後,返回計算結果.

    std::future<int> answer = std::async([] {
        std::stringstream stm;
        stm << "future id:" << std::this_thread::get_id() << std::endl;
        std::cout << stm.str();
        int sum = 0;
        for (int i = 1; i <= 100; i++)
        {
            sum += i;
            std::cout << i << " ";
        }
        std::cout << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));  // 增加延遲(1s)
        return sum;
    });
    std::stringstream stm;
    stm << "main id:" << std::this_thread::get_id() << std::endl;
    std::cout << stm.str();
    std::cout << "answer is: " << answer.get() << std::endl; // 此時會被阻塞, 直到異步任務返回
    std::cout << "tag 2" << std::endl;

(2) std::async 允許通過添加額外的調用參數, 向函數傳遞額外的參數.
  如果第一個參數是一個指向成員函數的指針, 第二個參數提供有這個函數成員類的具體對象(可以通過指針, 或者包裝在 std::ref 中), 剩余的參數可作為成員函數的參數傳入.
  否則, 隨後的所有參數將作為函數的參數, 或作為指定可調用對象的第一個參數. 比如 std::thread, 當參數為右值(rvalues)時, 拷貝操作將使用移動的方式轉移原始數據. 這就允許使用“只移動”類型作為函數對象和參數.

    class XFun {
    public:
        XFun() {}
        ~XFun() {}

        void f(const std::string& str) {
            std::stringstream stm;
            stm << "f called. " << this << "-->" << str << std::endl;
            std::cout << stm.str();
        }
        std::string g(const std::string& str) {
            std::stringstream stm;
            stm << str << "[--> add by function g] " << this;
            return stm.str();
        }
        //XFun& operator=(const XFun&) = delete;
        //XFun(const XFun&) = delete;

        void operator()(const std::string& str) {
            std::stringstream stm;
            stm << "operator() called. " << this << "-->" << str << std::endl;
            std::cout << stm.str();
        }
    };
    XFun x;
    std::cout << "addr of x:" << &x << std::endl;
    std::async(&XFun::f, &x, std::string("test f()"));
    std::future<std::string> f2 = std::async(&XFun::g, x, std::string("test g() temp")); // 創建一個 x 對象的副本傳入, 刪除賦值函數後, 將不能編譯
    std::async(std::ref(x), std::string("test operator()"));
    std::async(XFun(), std::string("test operator() temp")); // 創建一個 XFun 的臨時對象傳入
    std::cout << f2.get() << std::endl;

(3) 默認情況下, std::async 會啟動一個新線程來完成任務, 但是也可以指定額外的執行方式:
  std::launch::defered 指定等到 wait 或 get 被調用時才執行.
  std::launch::async 指定必須到獨立的線程中執行.
  默認為: std::launch::defered | std::launch::async

    auto f3 = std::async(std::launch::deferred, [] {
        std::stringstream stm;
        stm << "f3 called. TID:" << std::this_thread::get_id() << std::endl;
        std::cout << stm.str();
    });
    auto f4 = std::async(std::launch::async, [] {
        std::stringstream stm;
        stm << "f4 called. TID:" << std::this_thread::get_id() << std::endl;
        std::cout << stm.str();
    });
    std::stringstream stm;
    stm << "main. TID:" << std::this_thread::get_id() << std::endl;
    std::cout << stm.str();
    std::this_thread::sleep_for(std::chrono::seconds(1));
    f3.wait();

Copyright © Linux教程網 All Rights Reserved