Skip to content

Latest commit

 

History

History
35 lines (23 loc) · 2.9 KB

jthread.md

File metadata and controls

35 lines (23 loc) · 2.9 KB

Threads joining

А вы уже заметили, что в предыдущих заметках я использую std::jthread из C++20 вместо std::thread? И зачем?

А все очень просто: деструктор std::thread дурной.

Везде, где может начать вызываться деструктор std::thread, нужно втыкать

// std::thread t1;
if (t1.joinable()) { // Если вы не уверены в богатой жизненной истории
                     // объекта t1, обязательно выполняйте эту проверку
    t1.join(); // или t1.detach()
}

Чтобы ознаменовать свое желание (или нежелание) дожидаться окончания выполнения потока. Иначе деструктор потока повалит вашу программу, вызвав std::terminate. Очень удобно и очень по RAII-шному, неправда ли?

Нет, конечно, совсем везде втыкать не надо. Если вы знаете, что кто-то другой уже выполнил это заклинание, или содержимое объекта std::thread переместили в другой объект (t2 = std::move(t1)).

И тем более не надо просто так втыкать этот код, обращающийся к одному и тому же объекту std::thread из разных потоков. Иначе — race condition. Надо синхронизировать.

И, конечно же, убедитесь что этот код ни в коем случае не будет выполняться параллельно с вызовом деструктора t1; Деструктор тоже вызывает joinable, а это опять race condition.

Собираетесь сделать обертку над std::thread, чтобы вызывать join в ее деструкторе? Спешу порадовать: join/detach кидают исключения. Со всеми вытекающими проблемами.

Здорово, да? Поэтому в примерах был и будет std::jthread. Его деструктор сам выполняет join и снимает хотя бы часть головной боли.

А если вас join не устраивает, не хотите ждать и пользуетесь detach... Ну что ж. Право ваше. Только помните, что все потоки резко и внезапно помрут, когда закончится main.

Полезные ссылки

  1. https://en.cppreference.com/w/cpp/thread/thread
  2. https://en.cppreference.com/w/cpp/thread/jthread