2016-02-05 82 views
3

pthreads是未定義的行爲,如果多個線程試圖加入同一個線程:多個線程可以加入相同的boost :: thread嗎?

如果多個線程同時嘗試與同一個線程加入, 結果是不確定的。

對於boost::thread s也是如此嗎?該文檔似乎沒有指定這一點。

如果它是未定義的,那麼多線程等待一個線程完成的乾淨方式是什麼?

+0

嗯,有趣的是,它不是在N4296 c項++標準草案,我可以讀。我會說這是UB和/或「不這樣做」的行爲。 :) – wilx

+1

其他線程可以測試一個線程是否爲'joinable()',或者閉合線程可以使用'condition_variable'來表示它的所有工作已經完成(即使它仍然可以運行) – Tas

+2

@wilx,'std :: thread :: join()'是一個非const函數,因此同時調用它是一個數據競爭,即未定義的行爲。除非另有規定,該規則適用於所有標準庫類型。 –

回答

2

如果它是未定義的,那麼多線程等待一個線程完成的乾淨方式是什麼?

的清潔方式將是一個線程通知其他人,這是完整的。 A packaged_task包含一個可以等待的future,這可以幫助我們在這裏。

這是一種方法。我已經使用std :: thread和std :: packaged_task,但你也可以使用boost等價物。

#include <thread> 
#include <mutex> 
#include <future> 
#include <vector> 
#include <iostream> 

void emit(const char* msg) { 
    static std::mutex m; 
    std::lock_guard<std::mutex> l(m); 
    std::cout << msg << std::endl; 
    std::cout.flush(); 
} 

int main() 
{ 
    using namespace std; 

    auto one_task = std::packaged_task<void()>([]{ 
     emit("waiting..."); 
     std::this_thread::sleep_for(std::chrono::microseconds(500)); 
     emit("wait over!"); 
    }); 

    // note: convert future to a shared_future so we can pass it 
    // to two subordinate threads simultaneously 
    auto one_done = std::shared_future<void>(one_task.get_future()); 
    auto one = std::thread(std::move(one_task)); 

    std::vector<std::thread> many; 
    many.emplace_back([one_done] { 
     one_done.wait(); 
     // do my thing here 
     emit("starting thread 1"); 
    }); 

    many.emplace_back([one_done] { 
     one_done.wait(); 
     // do my thing here 
     emit("starting thread 2"); 
    }); 

    one.join(); 
    for (auto& t : many) { 
     t.join(); 
    } 

    cout << "Hello, World" << endl; 
    return 0; 
} 

預期輸出:

waiting... 
wait over! 
starting thread 2 
starting thread 1 
Hello, World 
0

我結束了使用boost::condition_variable ...大致爲:

class thread_wrapper { 
    boost::mutex mutex; 
    boost::condition_variable thread_done_condition; 
    bool thread_done = false; 

    void the_func() { 
     // ... 
     // end of the thread 
     { 
      boost:unique_lock<boost::mutex> lock(mutex); 
      thread_done = true; 
     } 
     thread_done_condition.notify_all(); 
    } 

    void wait_until_done() { 
     boost::unique_lock<boost::mutex> lock(mutex); 
     thread_done_condition.wait(lock, [this]{ return thread_done; }); 
    } 
} 

然後多個來電可以安全地調用wait_until_done()

0

這讓我覺得現在像本來還制定了以下內容:

class thread_wrapper { 
public: 
    thread_wrapper() : thread([this]() { this->the_func(); }) { } 

    void wait_until_done() { 
     boost::unique_lock<boost::mutex> lock(join_mutex); 
     thread.join(); 
    } 

private: 
    void the_func() { 
     // ... 
    } 

    boost::mutex join_mutex; 
    boost::thread thread; 
} 
相關問題