2016-02-05 3 views
3

pthreads имеет неопределенное поведение, если несколько потоков пытаются присоединиться к той же нити:Может ли несколько потоков присоединиться к одному и тому же boost :: thread?

Если несколько потоков одновременно пытаются присоединиться к одной и той же теме, результаты не определены.

То же самое верно для boost::thread s? В документации не указано это.

Если это не определено, то какой будет чистый путь для нескольких потоков, чтобы ждать по одному потоку?

+0

Хм, интересно, он не упоминается в N4296 C++ стандартный проект, который я могу читать. Я бы сказал, что это тогда поведение UB и/или «не делайте этого». :) – wilx

+1

Другие потоки могли бы проверить, был ли поток «joinable()», или закрывающий поток мог использовать «condition_variable», чтобы сигнализировать, что все его работы завершены (хотя он все еще работает _may_) – Tas

+2

@wilx, 'std :: thread :: join() 'является неконстантной функцией, поэтому одновременным вызовом является гонка данных, то есть неопределенное поведение. Это правило применяется ко всем типам стандартных библиотек, если не указано иное. –

ответ

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; 
} 
Смежные вопросы