2016-02-05 86 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; 
} 
相关问题