2016-08-24 49 views
1

假設您希望並行運行一個節,然後合併回主線程,然後再並行回到節,依此類推。類似於童年遊戲的紅燈綠燈。C++分叉連接並行阻塞

我已經給出了一個我想要做的例子,我使用一個條件變量在開始時阻止線程,但希望並行地啓動它們,但是最後阻止它們他們可以連續打印出來。 * =操作可能是一個跨越數秒的更大的操作。重用線程也很重要。使用任務隊列可能太重了。

我需要使用某種形式的阻塞結構,它不僅僅是一個簡單的忙碌循環,因爲我知道如何用繁忙循環來解決這個問題。

在英國:

  1. 線索1產生10個線程被阻塞
  2. 線程1個信號的所有線程開始(而不阻斷海誓山盟)
  3. 螺紋2-11處理其專用存儲器
  4. 線程1正在等待2-11完成(可以在這裏使用原子計數)
  5. 線程2-11完成,每個線程都可以通知1以檢查其條件(如有必要)
  6. 線程1個檢查其狀態並打印陣列
  7. 線程1個resignals 2-11再次處理,由2-

實施例的代碼(幼稚適於從例如在cplusplus.com)繼續:

// condition_variable example 
#include <iostream>   // std::cout 
#include <thread>    // std::thread 
#include <mutex>    // std::mutex, std::unique_lock 
#include <condition_variable> // std::condition_variable 
#include <atomic> 

std::mutex mtx; 
std::condition_variable cv; 
bool ready = false; 
std::atomic<int> count(0); 

bool end = false; 
int a[10]; 

void doublea (int id) { 
    while(!end) { 
    std::unique_lock<std::mutex> lck(mtx); 
    while (!ready) cv.wait(lck); 
    a[id] *= 2; 
    count.fetch_add(1); 
    } 
} 

void go() { 
    std::unique_lock<std::mutex> lck(mtx); 

    ready = true; 
    cv.notify_all(); 
    ready = false; // Naive 

    while (count.load() < 10) sleep(1); 
    for(int i = 0; i < 10; i++) { 
    std::cout << a[i] << std::endl; 
    } 

    ready = true; 
    cv.notify_all(); 
    ready = false; 
    while (count.load() < 10) sleep(1); 
    for(int i = 0; i < 10; i++) { 
    std::cout << a[i] << std::endl; 
    } 

    end = true; 
    cv.notify_all(); 
} 

int main() { 
    std::thread threads[10]; 
    // spawn 10 threads: 
    for (int i=0; i<10; ++i) { 
    a[i] = 0; 
    threads[i] = std::thread(doublea,i); 
    } 

    std::cout << "10 threads ready to race...\n"; 
    go();      // go! 

    return 0; 
} 
+0

爲什麼'count'原子?爲什麼在一邊使用條件變量並在另一邊使用繁忙的睡眠? – UmNyobe

+0

@UmNyobe我明確不想使用繁忙的睡眠。線程應該在等待被通知的時候睡覺。 對於你的另一個問題,count是原子的,因爲它可以通過多個線程同時增加一些運氣。增量是一個兩階段過程。 –

回答

1

這並不是微不足道的實施它有效。此外,除非你正在學習這個主題,否則它沒有任何意義。條件變量在這裏不是一個好的選擇,因爲它不能很好地擴展。

我建議你看看運行時庫如何實現fork-join並行機制並向他們學習或在你的應用中使用它們。請參閱http://www.openmprtl.org/,http://opentbb.org/,https://www.cilkplus.org/ - 所有這些都是開源的。

OpenMP是您尋找的最接近的模型,它具有最高效的fork-join障礙實現。雖然它有其缺點,因爲它是爲HPC而設計的,並且缺乏動態可組合性。 TBB和Cilk最適合嵌套並行和模塊和庫中的使用,可用於外部並行區域的上下文中。

+0

你說我正在嘗試學習是正確的。我以前看過TBB和OpenMP,但是OpenMP大量使用編譯指令的時間已經到了,而TBB有很多用於簡單工作的鍋爐板。 但是,我很樂意再給他們看看並使用它們。爲了真正閱讀我的問題,我會給你答案。 –

+0

您不想混合下面的前端(使用模型)和運行時庫。您可以爲任何這些運行時編寫自己的前端。 – Anton

0

您可以使用屏障或條件變量來啓動所有線程。然後,線程可以等待所有線程結束其工作(通過所有線程上的聯接方法結束工作),然後打印一個用於循環其數據的線程。

+0

這不是一個解決方案,因爲一旦加入就需要重新創建線程。 –