2015-11-03 56 views
0

我有以下程序(由例子!):同步三個線程在C++

#include<thread> 
#include<mutex> 
#include<iostream> 

class MultiClass { 
    public: 
     void Run() { 
      std::thread t1(&MultiClass::Calc, this); 
      std::thread t2(&MultiClass::Calc, this); 
      std::thread t3(&MultiClass::Calc, this); 
      t1.join(); 
      t2.join(); 
      t3.join(); 
     } 
    private: 
     void Calc() { 
      for (int i = 0; i < 10; ++i) { 
       std::cout << i << std::endl; 
      } 
     } 
}; 

int main() { 
    MultiClass m; 
    m.Run(); 
    return 0; 
} 

我需要的是同步的循環迭代通過以下方式和我不能拿出一個解決方案(I」一直在擺弄了約一個小時,現在使用互斥體,但無法找到組合): t1t2應做一個循環迭代,然後t3應做一個迭代,然後再t1t2應做一個,然後t3應做一個。

所以你看,我需要t1t2同時做事情和經過一次迭代,t3應該自己做一個迭代。

你能指點一下我該怎麼做到嗎?就像我說的那樣,我一直在用互斥體嘗試這個,並且不能提出解決方案。

+0

爲什麼要創建3線程,最多允許2個並行運行? – MikeMB

+0

1.解釋說明只有2個線程並行運行,2.這取決於您的硬件。在現代CPU上可以並行運行更多的兩個線程(例如,使用HT的雙核心的四核) – Nidhoegger

+0

在您的示例中,您正在創建3個Thread對象,其中只允許2個並行邏輯運行。這通常意味着你失去了表現。我在問爲什麼會出現這種情況,因爲有不同的可能性來實現你想要的功能,但根據你的程序結構的原因,有一種可能比另一種更可取。 – MikeMB

回答

1

如果你真的想用手工給定線程結構要做到這一點,你可以用這樣的東西*:

class SyncObj { 
    mutex mux; 
    condition_variable cv; 
    bool completed[2]{ false,false }; 

public: 
    void signalCompetionT1T2(int id) { 
     lock_guard<mutex> ul(mux); 
     completed[id] = true; 
     cv.notify_all(); 
    } 
    void signalCompetionT3() { 
     lock_guard<mutex> ul(mux); 
     completed[0] = false; 
     completed[1] = false; 
     cv.notify_all(); 
    } 
    void waitForCompetionT1T2() { 
     unique_lock<mutex> ul(mux);    
     cv.wait(ul, [&]() {return completed[0] && completed[1]; });   
    } 
    void waitForCompetionT3(int id) { 
     unique_lock<mutex> ul(mux);   
     cv.wait(ul, [&]() {return !completed[id]; });   
    }  
}; 

class MultiClass { 
public: 
    void Run() { 
     std::thread t1(&MultiClass::Calc1, this); 
     std::thread t2(&MultiClass::Calc2, this); 
     std::thread t3(&MultiClass::Calc3, this); 
     t1.join(); 
     t2.join(); 
     t3.join(); 
    } 
private: 
    SyncObj obj; 
    void Calc1() { 
     for (int i = 0; i < 10; ++i) { 
      obj.waitForCompetionT3(0); 
      std::cout << "T1:" << i << std::endl; 
      obj.signalCompetionT1T2(0); 
     }   
    } 
    void Calc2() { 
     for (int i = 0; i < 10; ++i) { 
      obj.waitForCompetionT3(1); 
      std::cout << "T2:" << i << std::endl; 
      obj.signalCompetionT1T2(1); 
     } 
    } 
    void Calc3() {  
     for (int i = 0; i < 10; ++i) { 
      obj.waitForCompetionT1T2(); 
      std::cout << "T3:" << i << std::endl; 
      obj.signalCompetionT3(); 
     }  
    } 
}; 

但是,這只是一個合理的方法,如果每次迭代的計算都很昂貴,那麼您可以忽略同步開銷。如果情況並非如此,那麼你應該更好地看看像intel的tbb或microsofts ppl這樣的適當的並行編程庫。

*)注意:此代碼未經測試且未優化。我只是寫了它來顯示一般結構可能看起來像什麼

+0

這真是太棒了!謝謝! – Nidhoegger

1

使用兩個條件變量,這裏是一個草圖..

線程1 & 2條件變量segment_1等待:

std::condition_variable segment_1; 

線程條件變量segment_2 3個等待;

std::condition_variable segment_2; 

線程1 & 2應該wait()segment_1和線程3 segment_2應該wait()。爲了揭開序幕線程1 & 2,撥打notify_all()segment_1,一旦他們完成後,調用notify_one()segment_2開球線3.您可能需要使用一些控制線程控制序列,除非你能鏈(即一次1 & 2完成後,最後一個完成調用notify在線程3等..)

這是不完美的(見失去了喚醒)

+0

我同意這樣的方法,因爲每個線程都應該有自己的線程ID,它可以用來檢查它應該做什麼:if((myId == 1)||(myId == 2)){wait (segment_1); } else {wait(segment_2); } –

+0

在我的主程序線程中有一個ID,忘記提及了!感謝這種方法! – Nidhoegger