Одинаково ли безопасно переместить вызов соединения внутрь блока try?

У меня есть вопрос/сомнение по поводу следующего фрагмента книги «Параллелизм C++». Я хочу знать, есть ли техническая причина(ы) для размещения t.join() после блока try catch вместо помещения его внутри блока try.

//callable whose defintion is not related to this question
struct my_func; 
void f()
 {
  int some_local_state = 0;
  func my_func(some_local_state);
  std::thread t(my_func);
  try {
    do_something_in_current_thread();
    //can we put/move the t.join() here? instead of having it at point #2
  } catch (...) {
    t.join();
    throw;
  }
  //author put the t.join() here why not inside try block
  t.join(); //#2
}

Как видите, автор поставил t.join() в точку #2. Но я хочу знать, почему бы нам просто не разместить его внутри самого блока try, сразу после вызова do_something_in_current_thread(). Я имею в виду, есть ли какие-либо технические случаи/преимущества размещения его в #2 вместо внутри try блока, о которых я, возможно, не знаю, поскольку я только начал изучать многопоточность.

Как новичок, я не могу придумать ни одного случая/преимущества наличия его в #2 вместо этого внутри блока try.

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

Почему отрицательные голоса. В этом вопросе нет ничего плохого. Я разместил код в виде текста, указал источник и четко выразил свои сомнения.

Alan 02.08.2024 14:18

Некоторые рекомендации имеют тенденцию минимизировать код в блоке try (меньше кода для проверки на исключение).

Jarod42 02.08.2024 14:45

Кстати, thread::join может сам генерировать исключение.

Jarod42 02.08.2024 14:47
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
63
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

почему бы не внутри блока try

Вы можете переместить второй join() в блок try, поскольку оба пути приведут к присоединению к потоку, так же, как если бы join() сохранялся в конце функции.

Нет никаких технических причин отдавать предпочтение одному другому.

Обратите внимание, что в C++20 этой ситуации можно избежать, используя вместо этого автоматическое объединение std::jthread:

void f() {
  int some_local_state = 0;
  func my_func(some_local_state);
  std::jthread t(my_func);
  do_something_in_current_thread();
}
thread::join может сам генерировать исключение... поэтому в таких случаях оба кода могут вести себя по-разному. Хотя из возможных случаев, похоже, нет :-) .
Jarod42 02.08.2024 14:54

@Jarod42 Да, если join() выпадает в этом сценарии, должно быть, происходит что-то действительно подозрительное :-)

Ted Lyngmo 02.08.2024 15:11

Я неправильно понял, кого join тронуло это предложение.

François Andrieux 02.08.2024 15:31

Если вы хотите, чтобы что-то произошло в условиях броска или отсутствия броска, вы можете использовать защиту с оптическим прицелом. Минимальный пример этого:

#include <thread>
#include <functional>

void do_something_in_current_thread()
{};

class simple_scope_guard
{
public:
    simple_scope_guard(std::function<void> fn) :
        guard{ fn }
    {
    }

    ~simple_scope_guard()
    {
        guard();
    }
private:
    std::function<void> guard;
};

struct my_func;
void f()
{
    int some_local_state = 0;
    std::thread t([] {});

// start a scope to manage the lifetime of the scope guard
    { 
        simple_scope_guard scope_guard{ [&] { t.join(); } };
        do_something_in_current_thread();
        // whether do_something throws or not scope_guard will go out of scope and 
        // call thread.join
    }
}

Я проголосовал против, потому что ОП прямо сказал: «Обратите внимание, что я знаю, что в последнем разделе книги также есть jthread, но я не ищу обходной путь. Вместо этого я спрашиваю только о данном коде». Им не интересно знать другие пути решения этого вопроса. Вместо этого они задали конкретный вопрос по поводу данного фрагмента.

user12002570 02.08.2024 14:42

На мой взгляд, защита области - это не обходной путь, а широко используемый шаблон (в сценариях try/catch, наконец). Но не стесняйтесь понижать голосование, если считаете, что это обходной путь;)

Pepijn Kramer 02.08.2024 15:22

Я хочу сказать, что ОП уже знает об охране области действия. Им не нужна защита области или что-то еще, кроме информации о размещении t.join() в цитируемой ссылке из книги.

user12002570 02.08.2024 15:41

Читаю вопрос еще раз: вы правы. Я оставлю это здесь для других

Pepijn Kramer 02.08.2024 15:45

Другие вопросы по теме