C ++ более зависим от своего стека вызовов, чем C. Программы на C ++ часто используют RAII, что означает, что ресурсы связаны с объектами, которые часто живут в стеке. Пользователи таких объектов ожидают, что эти объекты будут уничтожены должным образом. Если функция создает объект стека, она ожидает, что в какой-то момент в будущем управление вернется к этой функции, и объект стека будет уничтожен.
Таким образом, для потока с некоторым механизмом не существует глубина стека до go. std::thread
заканчивается только тогда, когда достигнут конец функции, переданной конструктору thread
(исключение, вызванное функцией потока, вызывает std::terminate
).
Учитывая это, лучше реструктурировать код, чтобы вам никогда не приходилось вызывать функцию потока для выхода из какого-то произвольного места в графе вызовов. Сделайте так, чтобы единственными точками, в которых вы хотели бы выйти из текущего потока, были места в основной функции потока.
Например, типичный способ работы пула потоков состоит в том, что каждый поток Функция main переходит в режим ожидания, ожидая, когда какая-либо форма задачи будет удалена для этого потока. Когда задача доступна, она выполняет эту задачу. По завершении задачи она проверяет наличие новой задачи и, если ее нет, возвращается в спящий режим до тех пор, пока задача не будет готова.
В таком пуле потоков ни один поток никогда не останавливается . Отдельные задачи останавливаются, но фактическое std::thread
является вечным (или, по крайней мере, живет так же долго, как и пул).
Если задача должна завершиться, то такое завершение, по сути, представляет собой неисполнение задачи. В C ++ это пишется как «выбрасывание исключения». Основной поток помещает все вызовы задач в блок try
, с блоком catch
для указанного типа исключения c. Затем он может сообщить кому-либо о сбое задачи, а затем go проверить наличие новой задачи.
И это гарантирует, что стек вызовов задачи очищен.