2016-01-21 60 views
1

有沒有辦法啓動兩個(或更多)C++ 11線程和join()完成的第一個線程?C++ 11加入完成的第一個線程

一個示例場景:

#include <iostream> 
#include <thread> 

using namespace std;  
void prepare_item1() {std::cout << "Preparing 1" << std::endl;}  
void consume_item1() {std::cout << "Consuming 1" << std::endl;}  
void prepare_item2() {std::cout << "Preparing 2" << std::endl;}  
void consume_item2() {std::cout << "Consuming 2" << std::endl;} 

int main() 
{ 
    std::thread t1(prepare_item1); 
    std::thread t2(prepare_item2); 

    t1.join(); 
    consume_item1(); 

    t2.join(); 
    consume_item2(); 

    return 0; 
} 

我也喜歡做這樣的事情,而不是:

int main() 
{ 
    std::thread t1(prepare_item1); 
    std::thread t2(prepare_item2);  

    finished_id=join_any(t1,t2) 
    if (finished_id==1) 
    { 
     consume_item1(); 
     ... 
    } 
    else if (finished_id==2) 
    { 
     consume_item2(); 
     ... 
    } 

    return 0; 
} 

另外,我想解決會阻止,類似於t.join ()函數。

注:我需要這個的真正原因是我有兩個不同的阻塞函數,我從它們接收命令,並且每當它們中的任何一個準備好時,我想處理第一個到達的命令並繼續到下一個命令它完成了。 (來自兩個並行源的命令的順序處理)

謝謝!

+0

我最初會說不,但我確定如果你註冊中斷,你可能會以這種特定的方式做到這一點。 – SGM1

+1

你需要的是'std :: condition_variable' http://en.cppreference.com/w/cpp/thread/condition_variable – arainone

+1

爲了進一步解釋,'std :: condition_variable'會在所有線程間共享。主線程,即你阻塞的線程,將通過首先調用'notify_one'的任何線程(t1或t2)來發信號。 – arainone

回答

2

這裏是一個線程安全的多生產多消費隊列:

template<class T> 
struct safe_queue { 
    std::deque<T> data; 
    std::atomic<bool> abort_flag = false; 
    std::mutex guard; 
    std::condition_variable signal; 

    template<class...Args> 
    void send(Args&&...args) { 
    { 
     std::unique_lock<std::mutex> l(guard); 
     data.emplace_back(std::forward<Args>(args)...); 
    } 
    signal.notify_one(); 
    } 
    void abort() { 
    abort_flag = true; // 1a 
    { std::unique_lock<std::mutex>{guard}; } 
    signal.notify_all(); // 1b 
    }   
    std::experimental::optional<T> get() { 
    std::unique_lock<std::mutex> l(guard); 
    signal.wait(l, [this]()->bool{ // 2b 
     return !data.empty() || abort_flag.load(); // 2c 
    }); 
    if (abort_flag.load()) return {}; 
    T retval = std::move(data.front()); 
    data.pop_front(); 
    return retval; 
    } 
}; 

有線程數據推入隊列,主線程就可以做一個.get()

如果調用了abort(),則所有等待的線程都將被一個來自.get()的「空」值喚醒。

它使用std::experimental::optional,但你可以用別的東西替換它(拋出放棄?無論如何)。

代碼從this other answer略有修改。請注意,我認爲其他答案有一些錯誤,我在上面進行了更正,並試圖解決不同的問題。

您發送的消息可能是準備等待的線程的id,或者它已完成的工作等。

相關問題