Параллельное программирование на С++ в действии. Практика разработки многопоточных программ | страница 24
Есть и другой способ — явно гарантировать, что поток завершит исполнение до выхода из функции, присоединившись к нему.
2.1.2. Ожидание завершения потока
Чтобы дождаться завершения потока, следует вызвать функцию >join()
ассоциированного объекта >std::thread
. В листинге 2.1 мы можем заменить вызов >my_thread.detach()
перед закрывающей скобкой тела функции вызовом >my_thread.join()
, и тем самым гарантировать, что поток завершится до выхода из функции, то есть раньше, чем будут уничтожены локальные переменные. В данном случае это означает, что запускать функцию в отдельном потоке не имело смысла, так как первый поток в это время ничего не делает, по в реальной программе исходный поток мог бы либо сам делать что-то полезное, либо запустить несколько потоков параллельно, а потом дождаться их всех.
Функция >join()
дает очень простую и прямолинейную альтернативу — либо мы ждем завершения потока, либо нет. Если необходим более точный контроль над ожиданием потока, например если необходимо проверить, завершился ли поток, или ждать только ограниченное время, то следует прибегнуть к другим механизмам, таким, как условные переменные и будущие результаты, которые мы будем рассматривать в главе 4. Кроме тот, при вызове >join()
очищается вся ассоциированная с потоком память, так что объект >std::thread
более не связан с завершившимся потоком — он вообще не связан ни с каким потоком. Это значит, что для каждого потока вызвать функцию >join()
можно только один раз; после первого вызова объект >std::thread
уже не допускает присоединения, и функция >joinable()
возвращает >false
.
2.1.3. Ожидание в случае исключения
Выше уже отмечалось, что функцию >join()
или >detach()
необходимо вызвать до уничтожения объекта >std::thread
. Если вы хотите отсоединить поток, то обычно достаточно вызвать >detach()
сразу после его запуска, так что здесь проблемы не возникает. Но если вы собираетесь дождаться завершения потока, то надо тщательно выбирать место, куда поместить вызов