2009-08-07 4 views
22

Я пытаюсь написать довольно простое приложение с резьбой, но я новичок в библиотеке потоков boost. Простая тестовая программа, я работаю на это:(simple) boost thread_group question

#include <iostream> 
#include <boost/thread.hpp> 

int result = 0; 
boost::mutex result_mutex; 

boost::thread_group g; 

void threaded_function(int i) 
{ 
    for(; i < 100000; ++i) {} 

    { 
     boost::mutex::scoped_lock lock(result_mutex); 
     result += i; 
    } 
} 

int main(int argc, char* argv[]) 
{ 
    using namespace std; 

    // launch three threads 
    boost::thread t1(threaded_function, 10); 
    boost::thread t2(threaded_function, 10); 
    boost::thread t3(threaded_function, 10); 

    g.add_thread(&t1); 
    g.add_thread(&t2); 
    g.add_thread(&t3); 

    // wait for them 
    g.join_all(); 

    cout << result << endl; 

    return 0; 
} 

Однако, когда я скомпилировать и запустить эту программу, я получаю выход

$ ./test 
300000 
test: pthread_mutex_lock.c:87: __pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed. 
Aborted 

Очевидно, что результат является правильным, но я волнуюсь об этом сообщении об ошибке, особенно потому, что реальная программа, имеющая по существу ту же структуру, застревает в точке join_all(). Может кто-нибудь объяснить мне, что происходит? Есть ли лучший способ сделать это, то есть запустить несколько потоков, сохранить их во внешнем контейнере, а затем дождаться их завершения до продолжения программы?

Благодарим за помощь.

ответ

25

Я думаю, что проблема связана с деструктором thread_group, который вызывается, когда ваша программа выходит. Группа потоков хочет взять на себя ответственность за разрушение объектов потока. См. Также в документации boost::thread_group.

Вы создаете свои объекты потока в стеке как локальные переменные в области вашей основной функции. Таким образом, они уже были разрушены, когда программа выходит, и thread_group пытается их удалить.

В качестве решения, создавать объекты потоков в куче с новой и пусть thread_group заботиться об их уничтожении:

boost::thread *t1 = new boost::thread(threaded_function, 10); 
... 
g.add_thread(t1); 
... 
+0

Вы должны удалить многоточие между «новым» распределением памяти и передать его в thread_group. В противном случае, если что-то пойдет не так (то есть броски) в промежуточном коде, вы пропустите поток. –

+0

Да, это, по-видимому, так и было причиной ошибки в более крупной программе. В рабочем примере теперь используется: // запуск трех потоков g.add_thread (новый boost :: thread (threaded_function, 10)); g.add_thread (новый boost :: thread (threaded_function, 10)); g.add_thread (новый boost :: thread (threaded_function, 10)); – RandomGuy

+1

Хорошим способом убедиться, что вы не просочились, было бы использовать std :: unique_ptr или подобное решение и использовать ptr.get(), чтобы обеспечить поток для group_thread. – Klaim

2

add_thread() принимает на себя ответственность за поток, который вы передаете. Группа потоков удаляет поток. В этом примере вы удаляете память, выделенную в стеке, в значительной степени заглавное.

функция член add_thread()

недействительным add_thread (нить * thrd);

Предпосылка:

Выражение удаления thrd является хорошо сформирован и не приведет к неопределенному поведению.

Эффекты:

брать на себя ответственность форсирования :: нить объект, на который указывает thrd и добавить его к группе.

Постусловие:

этом-> размер() увеличивается на единицу.

Не уверен, что это не так в коде, или если это всего лишь пример ошибки. В противном случае код выглядит отлично.

24

Если вам не нужна ручка для ваших потоков, попробуйте использовать thread_group :: create_thread(), который устраняет необходимость в управлении нитку на всех:

// Snip: Same as previous examples 

int main(int argc, char* argv[]) 
{ 
    using namespace std; 

    // launch three threads 
    for (int i = 0; i < 3; ++i) 
     g.create_thread(boost::bind(threaded_function, 10)); 

    // wait for them 
    g.join_all(); 

    cout << result << endl; 

    return 0; 
} 
+0

create_thread все еще возвращает дескриптор потока http://www.boost.org/doc/libs/1_39_0/doc/html/thread/thread_management.html#thread.thread_management.threadgroup.create_thread. Причина, по которой create_thread может использоваться в этом случае, заключается в том, что в отличие от add_thread, группа потоков не несет ответственности за удаление потока. – shank22

0

Это выглядит ни один из выше фактически не ответил на вопрос.

Я встретил аналогичную проблему. Следствие этого предупреждения (pthread_mutex_lock.c: 87: __pthread_mutex_lock:. Утверждение `мьютекса -> _ данные _owner == 0' не удалось Отменено.) Является то, что иногда программа будет течь потоки и вызвать исключение boost_resource_error.

Причина в том, что программа продолжает выполняться после join_all(), хотя большая часть потоков все еще запущена (не завершена).