C++併發編程 異步任務

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();
相關文章
相關標籤/搜索