2014-01-09 67 views
4

也許我錯過了新std::async在C++ 11的正確用法異步不執行,但是這個聲明(超過在cppreference.com):的std ::指定發佈::當異步

如果異步標誌被設置(即策略& std :: launch :: async!= 0),然後異步在獨立的執行線程上執行函數f,就像由std :: thread(f,args ...)產生的一樣,除如果函數f返回一個值或引發異常,它將存儲在可通過std :: future訪問的共享狀態中,異步返回給調用者。

讓我覺得,我的線程應該與這一說法立即啓動:

std::async(std::launch::async, MyFunctionObject()); 

而不必等待調用std::future::get()。這似乎並非如此(使用MSVC 13編譯)。如果這不是由這個語句本身觸發的,如果我不關心std::future對象的返回值,該如何觸發?

實施例:

#include <thread> 
#include <iostream> 
#include <array> 
#include <future> 

static std::mutex write_mutex; 

class Cpp11Threads { 
public: 
    // Function operator for Function-Object 
    void operator()() { 
     const int num_threads = 50; 

     // Static std array 
     std::array<std::thread*, num_threads> worker_threads; 

     // Range based 
     for (std::thread*& thread : worker_threads) { 

      // Lambda expression 
      thread = new std::thread(
       [] { 
        static int i = 0; 
        write_mutex.lock(); 
        std::cout << "Hello, I am happy Std thread #" << i++ << std::endl; 
        write_mutex.unlock(); 
       }); 
     } 

     for (std::thread*& thread : worker_threads) { 
      thread->join(); 
      delete thread; 

      // nullptr instead of NULL 
      thread = nullptr; 
     } 
    } 
}; 

int main() { 
    std::async(std::launch::async, Cpp11Threads()); 
    return 0; 
} 
+0

你如何確定線程是否已經啓動?我在問,因爲'std :: async'這個咒語有着有趣的語義(即它是阻塞的)。 – juanchopanza

回答

9

啓動線程,你必須知道的第一件事是MSVC std::async符合C++ 11標準。

在C++ 11標準下,std::asyncstd::future返回值塊,直到std::async完成。

MSVC的實施沒有。這使得他們的std::async貌似更友好的使用,但在實踐中是相當棘手。

但是,由於std::async的行爲是根據std::thread來描述的,所以我們可以看看當您啓動std::thread並且無法清理時發生的情況。由此產生的std::thread被有效分離。一旦你退出main,C++標準不未指定會發生什麼這樣std::thread S,留給了你的具體實現。

基於一些快速的研究,當一個MSVC的Windows程序在主結束時,線程被終止。

總之,您的程序需要與您以某種方式啓動的線程重新同步,以便他們可以完成其任務,並防止主程序退出main。一個簡單的方法就是在任務中存儲返回的std::future,在main退出前存儲wait

如果您使用的是符合C++ 11的編譯器,則您嘗試的async將無法​​異步,因爲它會在銷燬返回的匿名std::future後立即阻止。

最後,請注意,啓動的thread等可能不會安排在創建後立即運行。他們如何以及何時運行是不可預測的。

C++ 11併發基元只是基元。其中許多人有古怪的行爲,如std::thread調用terminate這一事實,如果它被銷燬而不是detach ed或join ed和async的傾向,如果你不存儲future。它們可以用於簡單的任務,或用於編寫更高級別的庫,但它們不是用戶友好的。

+0

「如果你有一個符合C++ 11的編譯器,你嘗試的'async'將不會是異步的,因爲它會在它返回的匿名std :: future被破壞時立即阻塞。」這正是我想的,當'未來'超出範圍時,它會阻止,等待線程完成(或啓動它)。無賴MSVC的一部分。 –

2

我不精通C++ 11但AFAIK每個程序有一個主線程,它是其中的main()函數執行該線程。當該線程的執行完成時,程序將與其所有線程一起完成。如果你希望你的主線程等待其他線程,使用時必須使用像在Linux環境中

在pthread_join

(如果你手動創建你的線程),或正好

std :: future :: get()

在這個特定情況下。

退出主會殺死你的線程和你的情況可能阻止您在所有

+1

你說得對。由於我的主線程沒有使用future :: wait()等待線程沒有機會打印。半明顯的,但不直觀(在'async'之後添加'_sleep(10000)',讓它們都像魅力一樣打印),謝謝。 –

+1

@DannyA根據C++ 11,你的代碼應該阻塞,直到「異步」完成。 – juanchopanza

+1

@DannyA哦,它似乎[VS可能有一個錯誤](http://stackoverflow.com/questions/12508653/what-is-the-issue-with-stdasync)這意味着該調用是非阻塞的。 – juanchopanza