2015-05-12 87 views
3

我正在學習C++ 11中的新多線程技術。幾乎我在網上閱讀的所有教程都教導如何啓動執行功能的新線程(或多個線程),以後如何加入(或拆離)線程(或線程),以及如何避免使用mutex等的競速條件如何讓C++ 11線程運行多個不同的函數?

但是我沒有看到其中的任何一個顯示如何讓一個線程在程序的不同部分執行幾個函數。問題是,使用C++ 11線程,是否有可能實現以下目標?如果是這樣,怎麼樣? (舉個例子會很棒)。

void func1(std::vector<int> & data1){ ... } 

void func2(std::vector<int> & data2){ ... } 

// main function version I 
int main(){ 
    std::vector<int> data1; 
    // prepare data1 for func1; 
    std::thread t1(func1, std::ref(data1)); 

    std::vector<int> data2; 
    // prepare data2 for func2; 
    if (func1 in t1 is done){ 
     t1(func2, std::ref(data2)); 
    } 

    t1.join(); 
    return 0;  
} 

而且進一步,如果我想要把上述main函數體進入一個循環,如下什麼。可能嗎?如果是這樣,怎麼樣?從cplusplus.com

//main function version II 
int main(){ 
    std::vector<int> bigdata1; 
    std::vector<int> bigdata2; 

    std::thread t1; // Can I do this without telling t1 the function 
        // to be executed? 

    for(int i=0; i<10; ++i){ 
     // main thread prepare small chunk smalldata1 from bigdata1 for func1; 

     if(t1 is ready to execute a function){t1(func1, std::ref(smalldata1));} 

     // main thread do other stuff, and prepare small chunk smalldata2 from bigdata2 for func2; 

     if (func1 in t1 is done){ 
      t1(func2, std::ref(smalldata2)); 
     } 
    } 

    t1.join(); 
    return 0;  
} 
+3

爲什麼這個問題得到了downvoted?作爲學習C++ 11多線程的初學者,這不是一個合理的問題嗎? – Allanqunzi

+0

我在線程中並不是專家,但我認爲你可以使用['std :: condition_variable'](http://en.cppreference.com/w/cpp/thread/condition_variable)來創建第二個線程等待第一個。另外,如果你能夠接觸到[這本書](http://www.amazon。com/C-Concurrency-Action-Practical-Multithreading/dp/1933988770),你可能會從執行大部分'std :: thread'的人那裏學到很多東西。 – vsoftco

+1

你通常想要這樣的情況是一個線程安全的任務隊列和一個線程池來執行隊列中的任務。 'main'線程打包一個任務並將其推送到隊列中,池中的線程等待某些內容出現在隊列中,當它執行任務時,執行它,然後再等待隊列 –

回答

1

參考:

默認的構造構造一個線程對象,並不代表任何執行線程。

因此std::thread t根本沒有定義一個可執行的線程。線程函數必須在創建線程時提供,並且之後不能設置。

對於您的主要功能版本I,您將不得不創建兩個線程。東西如下所示:

int main(){ 
    std::vector<int> data1; 
    // prepare data1 for func1; 
    std::thread t1(func1, std::ref(data1)); 

    std::vector<int> data2; 
    // prepare data2 for func2; 
    t1.join(); // this is how you wait till func1 is done 

    // you will have to create a new thread here for func2 
    std::thread t2(func2, std::ref(data2)); 
    t2.join(); // wait for thread2 (func2) to end 

    return 0;  
} 

同樣,你可以把它們放在一個循環,這是正常的,這將給你主要功能版II

+0

所以,沒有辦法用一個線程來實現這一點。對於主函數版本II,在循環結束時,在't1.join()'和't2.join()'之後,你是否認爲我仍然可以在下一次迭代中使用't1'和't2' ?或者我需要殺死't1'和't2'並重新定義下一次迭代?調用'join'後會發生什麼?你怎麼殺死一個線程? – Allanqunzi

+0

@Allanqunzi沒有辦法在一個線程中完成它。不,你不能在'join'之後重複使用't1'和't2'。在調用'joint'之後,線程對象變成不可連接的,並且已經死了。對於你最後一個問題:你不能殺死C++中的線程([參考](http://stackoverflow.com/questions/13893060/i-want-to-kill-a-stdthread-using-its-thread-object)) 。給出的參考解釋了原因。 –

+0

謝謝!我認爲你有一個拼寫錯誤'joint'應該是'join'。 – Allanqunzi

1

C++ 11線程是旨在允許您編寫真實庫的原語。他們不容易使用。你應該包裹它們。

喜歡的東西:

struct tasks { 
    std::mutex m; 
    std::condition_variable v; 
    std::vector<std::packaged_task<void>> work; 
    std::vector<std::future<void>> finished; 
    void operator()(){ 
    while(true){ 
     std::packaged_task<void> f; 
     { 
     std::unique_lock<std::mutex> l(m); 
     if (work.empty()){ 
      v.wait(l,[&]{return !work.empty();}); 
     } 
     f = std::move(work.front()); 
     work.pop_front(); 
     } 
     if (!f.valid()) return; 
     f(); 
    } 
    } 
    std::future<void> do(std::function<void()> f){ 
    std::packaged_task<void> p(f); 
    auto r=p.get_future(); 
    { 
     std::unique_lock<std::mutex> l(m); 
     work.push_back(std::move(p)); 
     v.notify_one(); 
    } 
    return r; 
    } 
    void start(){ 
    finished.push_back(std::async(std::launch_policy::async, 
     std::ref(*this))); 
    } 
    ~tasks(){ 
    std::unique_lock<std::mutex> l(m); 
    for(auto&&unused:finished){ 
     work.push_back({}); 
    } 
    v.notify_all(); 
    } 
}; 

使用的樣子:

int main(){ 
    tasks t; 
    t.start(); 
    t.do([]({std::cout<<"hello ";}); 
    t.do([]({std::cout<<"world\n";}); 
} 

,如果你想知道當任務完成後,檢查未來do回報。

寫在手機上,沒有編譯,可能是完整的錯別字和錯誤,但一個地方開始。

不支持提前中止。易於編寫abaondon它清空work

支持多個消費者(workwe線程)我懷疑。在兼容系統上,dtor將等待所有線程完成排隊的作業。不在MSVC2013壽。

+0

感謝您的回覆。這是一個線程池的實現嗎?作爲初學者,我認爲我需要閱讀更多內容才能理解您的代碼。 – Allanqunzi

+0

@allan最初是一個工作任務,有一個線程正在執行任務,但是處理多個線程的池/能力有所下降。它寫得不好(「工作」向量隊列應該是別的東西,也許是一個deque,也許是別的東西),但基本的產品消費通知結構就在那裏。 – Yakk