К моменту вызова t.join() поток t уже мог завершиться, но тем не менее по стандарту все равно требуется вызвать либо join() либо detach() перед деструктором std::thread — иначе деструктор std::tread зовет std::terminate(). Объясните, пожалуйста, почему такое требование?
Здравствуйте, Максим Рогожин, Вы писали:
МР>К моменту вызова t.join() поток t уже мог завершиться, но тем не менее по стандарту все равно требуется вызвать либо join() либо detach() перед деструктором std::thread — иначе деструктор std::tread зовет std::terminate(). Объясните, пожалуйста, почему такое требование?
Чтобы не плодились ничейные висячие треды, очевидно. Этакий предохранитель.
Здравствуйте, Максим Рогожин, Вы писали:
МР>Почему висячие, если поток уже завершился?
Откуда ему, объекту ссылающемуся на поток, знать что он завершился? Это только в рантайме может выясниться. Насколько я знаю, от применения Terminate к уже завершённому потоку, никаких проблем быть не должно — если пользоваться WinApi. В С++ обёртке может быть и по-другому (тут я не знаю точно), например вызывается GetLastError, он выдаёт ненулевой результат и из-за того выбрасывается исключение.
Здравствуйте, Слава, Вы писали:
С>Откуда ему, объекту ссылающемуся на поток, знать что он завершился? Это только в рантайме может выясниться. Насколько я знаю, от применения Terminate к уже завершённому потоку, никаких проблем быть не должно — если пользоваться WinApi. В С++ обёртке может быть и по-другому (тут я не знаю точно), например вызывается GetLastError, он выдаёт ненулевой результат и из-за того выбрасывается исключение.
std::terminate() вызывает завершение всей программы. Если бы дело было только в висячих потоках — это была бы просто утечка ресурсов. Не обязательно было бы программу завершать.
МР>К моменту вызова t.join() поток t уже мог завершиться, но тем не менее по стандарту все равно требуется вызвать либо join() либо detach() перед деструктором std::thread — иначе деструктор std::tread зовет std::terminate(). Объясните, пожалуйста, почему такое требование?
во-первых, перед t.join() надо выполнить проверку t.joinable() иначе можем вылететь с исключением,
во-вторых, стандарт не может решить за программиста, какое поведение потока ему нужно. join() может повесить программу, detach() запросто может привести к висячим ссылкам. Вызов terminate() видимо показалось меньшим из зол Но никто не мешает написать свою RAII обёртку, которая будет вызывать join автоматом.
Здравствуйте, sergii.p, Вы писали:
SP>во-вторых, стандарт не может решить за программиста, какое поведение потока ему нужно. join() может повесить программу, detach() запросто может привести к висячим ссылкам. Вызов terminate() видимо показалось меньшим из зол
Если на момент вызова деструктора std::thread поток еще не завершился, то компилятор не может за программиста решить ждать завершения потока или нет.
Но если на момент вызова деструктора std::thread поток уже завершился, то зачем в этом случае звать std::terminate()?
Здравствуйте, Максим Рогожин, Вы писали:
МР>Но если на момент вызова деструктора std::thread поток уже завершился, то зачем в этом случае звать std::terminate()?
В этом запуске поток завершился, в следующем не успел. В этот раз программа не вызвала terminate, в следующий — вызвала. Потом 10 раз подряд не вызвала, а на 11 — вызвала.
Вам самому понравилось бы такое плавающее поведение?
Уж лучше один раз установить контракт, а не делать его зависимым от фазы луны.
Здравствуйте, Максим Рогожин, Вы писали:
МР>Если на момент вызова деструктора std::thread поток еще не завершился, то компилятор не может за программиста решить ждать завершения потока или нет.
МР>Но если на момент вызова деструктора std::thread поток уже завершился, то зачем в этом случае звать std::terminate()?
мне кажется, это можно было реализовать, но несколько усложнило бы логику работы. Получается созданному потоку надо будет информировать связанный класс std::thread о своём завершении. Это делается ради одного конкретного случая (несколько странного — фактически это эквивалентно вызову detach, но только без явного указания). Видимо намного проще написать в документации, что нужно всегда вызывать либо detach, либо join
Здравствуйте, Максим Рогожин, Вы писали:
МР>К моменту вызова t.join() поток t уже мог завершиться, но тем не менее по стандарту все равно требуется вызвать либо join() либо detach() перед деструктором std::thread — иначе деструктор std::tread зовет std::terminate(). Объясните, пожалуйста, почему такое требование?