LINUX.ORG.RU

многопоточное программирование. join

 


0

1

Доброго времени суток!

Задача такова: допустим, у нас есть (запущено) несколько потоков, каждый из которых, естественно, может завершиться в любой момент времени. Есть родительский для них процесс, который хочет вовремя определять, когда и кто из них остановился и при необходимости сразу перезапустить. Если бы у нас был один поток, то достаточно было бы простого join, но в случае нескольких - первый join должен заблокировать поток выполнения родительского процесса, пока не завершится первый поток и в этом случае остальные джоины не сработают. Решение вида «на каждый новый поток создавать еще поток-контролёр», конечно, сработает, но выглядит как-то вычурно и, подозреваю, что в нем тоже будут недостатки (поток сможет создать дочерний поток???).

Я где-то заблуждаюсь или эту задачу можно решить только используя процессы? В общем, как она решается?

★★

wait с проверкой кода возврата.

anonymous
()

если бы это была винда, С и и WinAPI, то подошёл бы вызов WaitForMultipleObjects()

в этой вашей жабе не знаю

Harald ★★★★★
()

А. метод гугления постфактум таки дал ссылку на ЛОР: тут

aido ★★
() автор топика
Ответ на: комментарий от Harald

Это не жаба, это - STL. В ней семафоров нема. Но даже если бы и были - накладные расходы от них великоваты.

aido ★★
() автор топика

Видимо, вариант один - слать родителю от потоков сообщение о завершении, чтобы их можно было присоединить.

aido ★★
() автор топика
Ответ на: комментарий от Harald

LFS неполной сборки для ARM. c++11, c99.

aido ★★
() автор топика

когда и кто из них остановился

А тебе точно нужно знать КТО из них остановился, а не просто заданное количество одновременно работающих потоков поддерживать?

Harald ★★★★★
()

Вот здесь описано решение, позволяющее запустить блок кода при завершении потока: http://stackoverflow.com/questions/20112221/invoking-a-function-automatically... Хотя, т.к. внутри дочернего потока нужно иметь возможность инициировать собственные действия, можно делать и гораздо проще. Что-то вроде:

void thread_func()
{
  struct do_at_exit_t {
    ~do_at_exit_t() { /* some code */ }
  } do_at_exit;

  call_application_specific_func();
}

На базе этого можно сделать простой механизм: объект, хранящий внутри номера завершившихся нитей, mutex и condition_variable. Этим объектом владеет родительский поток, ссылка на него передается в дочерние потоки. Дочерние потоки вешают специальный обработчик на завершение потока: захват mutex-а, выставление номера завершившейся нити, взвод condition_variable.

Родительская нить висит на condition_variable, просыпается, проверяет номера завершившихся дочерних нитей, делает join для них, перезапускает, опять засыпает на condition_variable.

Либо же для родительской нити делается event_queue, в которую дочерние нити запихивают сообщения о своем завершении. Родительская нить извлекает сообщения из event_queue и обрабатывает их соответствующим образом.

Впрочем, постановка задачи не очень понятна. Почему у вас вдруг потоки завершаются самопроизвольно и нуждаются в рестартах? Если есть желание повторить механизм супервизоров из Erlang, то для C++ уже есть готовые фреймворки с наличием таких вещей прямо из коробки.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Почему у вас вдруг потоки завершаются самопроизвольно и нуждаются в рестартах?

Хочется потренироваться в с++11/с99. Соответственно, пишу в виде демона WebServer и обработчик сообщений к нему. Так как у нас возможны аж 3 очереди сообщений (демону, веб-серверу и сообщения от обработчика), которые должны функционировать независимо, то должно быть 3 независимых потока. Сервер и обработчик могут выйти из-за ошибки. В зависимости от кода ошибки, может потребоваться его или присоединить с последующим завершением, или перезапустить.

aido ★★
() автор топика
Ответ на: комментарий от aido

при этом, WevServer написан с использованием Pthreads на С, а все остальное - на С++11.

aido ★★
() автор топика
Ответ на: комментарий от eao197

Хотя каковы разумные причины использовать именно связку языков или чистый С, вместо С++ - мне не ясно.

aido ★★
() автор топика
Ответ на: комментарий от aido

В зависимости от кода ошибки, может потребоваться его или присоединить с последующим завершением, или перезапустить.

Опасно применять к потокам внутри одно процесса те же самые подходы, что и к независимым процессам.

Когда процесс крэшиться, ОС подчищает за ним ресурсы и освобождает выделенную ему память.

Когда «вылетает» нить внутри одного процесса, то разработчик должен позаботиться, чтобы вылет не сопровождался мусором в памяти и неочищенными ресурсами.

Что ведет к тому, что у вас будет скорее всего что-то вроде:

void thread_func() {
  while( !shutdown_initiated ) {
    try {
      do_app_specific_code();
    }
    catch( const std::exception & x ) {
      ... // Some exception handling.
    }
  }
}
...
// In parent thread:
child[i] = std::thread{ thread_func };

Т.е. родительский поток не будет перезапускать сбойнувшие дочерние. Вместо этого сами дочерние потоки будут перезапускать внутри себя обработку чего-то там в случае исключений.

PS. Ну и если вы это делаете не удовольствия ради, то имело бы смысл все-таки обратить внимание на готовые фреймворки, в которых реализовано и управление потоками, и передача сообщений между ними.

eao197 ★★★★★
()
Ответ на: комментарий от aido

Я вам не предлагал использовать что-то вместо C++ :) Если условия задачи допускают использования как C, так и C++ (тем более C++11/14), то лично я не вижу причин писать на C, а не на C++. Но это мое личное мнение, т.к. опыт работы с C++ большой и форумные страшилки о C++ не пугают.

Если же в условиях задачи полный хардкор, вроде драйверов устройств, то тогда выбор plain C вполне себе разумен.

eao197 ★★★★★
()
Ответ на: комментарий от aido

Если совсем низкоуровневые, на основе которых можно выстраивать все, что угодно, то еще есть POCO и ACE.

Гораздо повыше уровнем будут вещи вроде TBB и HPX.

На задачи, требующие асинхронного обмена сообщениями хорошо ложится модель акторов. Для C++ есть ее реализации: C++ Actor Framework, Just::Thread Pro: Actors Edition (платная), SObjectizer.

Вот здесь еще можно посмотреть в разделе Concurrency.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Если же в условиях задачи полный хардкор, вроде драйверов устройств

Ну вот тут довольно жесткий выбор стоит. С одной стороны, ради увеличения скорости работы и снижения используемой памяти необходимо это все писать на уровне ядра на С, с другой - лучше купить устройство с чуть большей памятью, но зато появится разделение kernel/user-space и серверную часть можно будет сделать независимой от функционирования устройств. Тогда и чистый С не нужен на этом уровне задачи.

Изначально просто писал сервер на С из-за требования его запуска в отдельном треде, а треды с классами дружат плохо. Глупо.

Еще хуже стало, когда потребовалось сделать общение между потоками: по факту нужно было, чтобы все мьютексы и условные переменные создавались в самом веб-сервере (а он - на С), и передавались указатели на них в обработчик (а он - на С++, STL). В STL для этих штук нет конструктора копирования.

aido ★★
() автор топика
Ответ на: комментарий от aido

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

aido ★★
() автор топика

В общем, как она решается?

Если я твое наркоманское объяснение правильно понял, то thread pool + executor то, что тебе нужно.

cherry-pick
()
Ответ на: комментарий от aido

При чем тут колеса? Хотя да, ты их глотал, видимо... В общем, тебе что конкретно нужно? Пул воркеров?

cherry-pick
()
Ответ на: комментарий от aido

ThreadPool & Workers

на бусте реализуется несколько через жопу, но роботоспособно

MKuznetsov ★★★★★
()

Посылай в один канал сообщения из этих потоков о завершении и идентификаторе завершенного потока.

loz ★★★★★
()

Мне кажется, ты пишешь велосипед, при том неправильно вкорне. rtfm thread pool

invy ★★★★★
()
Ответ на: комментарий от Harald

Если что, то этот вызов велосипедится семафорами.

invy ★★★★★
()
Ответ на: комментарий от eao197

что только люди не делают, лишь бы не использовать pthread_cleanup_*

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.