Подтвердить что ты не робот

Когда следует использовать std:: thread:: detach?

Когда-то мне нужно использовать std::thread для ускорения моего приложения. Я также знаю, что join() ждет, пока поток не завершится. Это легко понять, но какая разница между вызовом detach() и не вызовом?

Я думал, что без detach() метод потока будет работать с использованием потока независимо.

Не отсоединяется:

void Someclass::Somefunction() {
    //...

    std::thread t([ ] {
        printf("thread called without detach");
    });

    //some code here
}

Вызов с отсоединением:

void Someclass::Somefunction() {
    //...

    std::thread t([ ] {
        printf("thread called with detach");
    });

    t.detach();

    //some code here
}
4b9b3361

Ответ 1

В деструкторе std::thread, std::terminate вызывается, если:

  • нить не была присоединена (с t.join())
  • и не был отключен (с t.detach())

Таким образом, вы должны всегда либо join, либо detach поток до того, как потоки выполнения достигнут деструктора.


Когда программа завершается (т.е. возвращается main), оставшиеся отсоединенные потоки, выполняемые в фоновом режиме, не ждут; вместо этого их выполнение приостанавливается и их локальные объекты потока уничтожаются.

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


Итак, следует ли использовать join или detach?

  • Используйте join
  • Если вам не требуется больше гибкости, и я хочу предоставить механизм синхронизации, чтобы дождаться завершения потока самостоятельно, и в этом случае вы можете использовать detach

Ответ 2

Вам следует вызвать detach, если вы не собираетесь ждать завершения потока с join, но вместо этого поток просто продолжит работать до тех пор, пока не выполнит его, а затем завершит работу, не ожидая, что основной поток будет ожидать его конкретно.

detach в основном высвободит ресурсы, необходимые для реализации join.

Это фатальная ошибка, если объект потока завершает свою жизнь, и ни join, ни detach не были вызваны; в этом случае вызывается terminate.

Ответ 3

Когда вы отсоединяете нить, это означает, что перед тем, как выйти из main(), вам не нужно join().

Библиотека потоков фактически ждет каждого такого потока ниже , но вы не должны заботиться об этом.

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

Ответ 4

По данным cppreference.com:

Отделяет поток выполнения от объекта потока, позволяя выполнение продолжить самостоятельно. Любые выделенные ресурсы будут освобожден после выхода из потока.

После вызова detach *this больше не принадлежит ни один поток.

Например:

  std::thread my_thread([&](){XXXX});
  my_thread.detach();

Обратите внимание на локальную переменную: my_thread, хотя время жизни my_thread истекло, будет вызван деструктор std::thread, и в деструкторе будет вызван std::terminate().

Но если вы используете detach(), вы больше не должны использовать my_thread, даже если время жизни my_thread истекло, с новым потоком ничего не произойдет.

Ответ 5

Этот ответ направлен на ответ на вопрос в названии, а не на объяснение различия между join и detach. Так когда же следует использовать std::thread::detach?

В должным образом поддерживаемом C++ коде std::thread::detach не следует использовать вообще. Программист должен убедиться, что все созданные потоки корректно завершаются, высвобождая все полученные ресурсы и выполняя другие необходимые действия по очистке. это означает, что отказ от владения потоками путем вызова detach не является вариантом, и поэтому join следует использовать во всех сценариях.

Однако некоторые приложения полагаются на старые и часто не очень хорошо разработанные и поддерживаемые API, которые могут содержать бесконечно блокирующие функции. Перемещение вызовов этих функций в отдельный поток, чтобы избежать блокировки других вещей, является обычной практикой. Невозможно изящно завершить такой поток, поэтому использование join приведет только к блокировке основного потока. Ситуация, когда использование detach будет менее злой альтернативой, скажем, выделению объекта thread с динамической длительностью хранения, а затем преднамеренной утечке.

#include <LegacyApi.hpp>
#include <thread>

auto LegacyApiThreadEntry(void)
{
    auto result{NastyBlockingFunction()};
    // do something...
}

int main()
{
    ::std::thread legacy_api_thread{&LegacyApiThreadEntry};
    // do something...
    legacy_api_thread.detach();
    return 0;
}