С++ 11: Что произойдет, если вы не вызываете join() для std:: thread
Ниже приводится:
void test()
{
std::chrono::seconds dura( 20 );
std::this_thread::sleep_for( dura );
}
int main()
{
std::thread th1(test);
std::chrono::seconds dura( 5 );
std::this_thread::sleep_for( dura );
return 0;
}
main
выйдет через 5 секунд, что произойдет с th1
, который все еще выполняется?
Продолжается ли выполнение до завершения, даже если объект потока th1
, который вы определили в main
, выходит из области действия и уничтожается?
Может ли th1
сидеть там после того, как он закончил выполнение или каким-то образом очистится, когда программа завершится?
Что делать, если поток был создан в функции, а не main
- работает ли поток до тех пор, пока программа не завершится или когда функция выходит из области видимости?
Можно ли просто не называть join
для потока, если вы хотите, чтобы какой-то тип тайм-аута в потоке?
Ответы
Ответ 1
Если вы не отсоединили или не присоединились к нити при вызове деструктора, он вызовет std::terminate
, мы увидим это, перейдя в черновик C + +11 стандарт, мы видим, что раздел 30.3.1.3
thread destructor говорит:
Если joinable(), вызывает std:: terminate(). В противном случае эффект не имеет. [ Примечание. Либо неявное разделение или объединение потока joinable() в его деструктор может привести к затруднению отладки правильности (для detach) или производительности (для объединения), возникающие только тогда, когда исключение. Таким образом, программист должен обеспечить, чтобы destructor никогда не выполняется, пока поток все еще соединяется. -конец примечание]
так как для обоснования этого поведения мы можем найти хорошее резюме в (Not), используя std:: thread
Почему деструктор соединяемого потока должен вызывать станд:: прекратить? В конце концов, деструктор может присоединиться к ребенку поток, или он может отсоединиться от дочернего потока, или он может отменить нить. Короче говоря, вы не можете присоединиться к деструктору, поскольку это приводят к неожиданному (не указанному явно в коде) программе замерзнуть в случае f2 бросков.
и пример следует, а также говорит:
Вы не можете отсоединиться, так как это будет рисковать ситуацией, когда основная нить оставляет область, в которую был запущен дочерний поток, и ребенок поток продолжает работать и сохраняет ссылки на область, которая уже ушел.
В статье упоминается N2802: просьба пересмотреть отрыв на уничтожение для объектов потока, что является аргументом против предыдущего предложения, которое было отсоединено от разрушение, если оно соединяется, и отмечает, что одна из двух альтернатив будет заключаться в том, чтобы присоединиться к ней, что может привести к взаимоблокировкам, другая альтернатива - это то, что мы имеем сегодня, которое является std::terminate
при уничтожении, если оно возможно.
Ответ 2
std::thread::~thread()
Если * имеет связанный поток (joinable() == true
), std::terminate()
называется
Источник: http://en.cppreference.com/w/cpp/thread/thread/~thread
Это означает, что программа, подобная этой, совсем не корректна или безопасна.
Обратите внимание, однако, что boost::thread::~thread()
вызывает detach()
вместо этого в этом случае.
(как пользователь dyp, указанный в комментариях, это поведение устарело в более поздних версиях)
Вы всегда можете обойти это с помощью RAII. Просто оберните свою нить внутри другого класса, которая будет иметь желаемое поведение при уничтожении.
Ответ 3
В С++ 11 вы должны явно указать "что происходит", когда вновь созданный поток выходит за пределы области (наш вызов dtor вызывается). Иногда, когда мы уверены, что основной поток продолжается, и наши потоки действуют как "конвейер", безопасно "отделять" их; и иногда, когда мы ждем, когда наши потоки WORKER завершат свои операции, мы присоединяем их к ним.
Как это, программист должен убедиться, что деструктор никогда не выполняется, пока поток все еще совместим.
Укажите многопоточную стратегию. В этом примере вызывается std::terminate()
.