Не смотря на то, что с многопоточностью имею дело уже больше 20 лет, при работе с голыми нитями нет-нет, да и нарываешься на неожиданности (а все потому, что когда пользуешься правильными инструментами, нужды работать с голыми потоками и нет). Вот минимальный пример, воспроизводящий проблему, с которой сегодня довелось столкнуться:
#include <thread> #include <vector> #include <chrono> #include <iostream> using namespace std; using namespace std::chrono; void run_threads( const vector< unsigned int > & times ) { vector< thread > threads; for( size_t i = 0; i <= times.size(); ++i ) threads.emplace_back( [t = times.at(i)]{ this_thread::sleep_for( seconds{t} ); } ); for( auto & t : threads ) t.join(); } int main() { try { run_threads( { 1, 2, 3, 4, 3, 2, 1 } ); } catch( const std::exception & x ) { std::cerr << x.what() << std::endl; } } |
Я тут намеренно спровоцировал выход за пределы вектора, дабы породить исключение. Только вот вместо нормального завершения после перехвата этого исключения программа под GCC/Clang падает с сообщением "terminate called without an active exception". Далеко не сразу удалось въехать, почему же так происходит...
Дело в том, что для уже стартовавших нитей не вызывается join. Что, видимо, и крешит приложение где-то в деструкторе std::thread.
Вот так. Казалось бы, везде объекты с деструкторами, посему и RAII должно быть во все поля... Ан нет: не вызвал join() явно -- получил гранату :) А все почему? А все потому, что не нужно с голыми потоками работать, лучше правильные инструменты использовать, которые берут на себя заботу о целой куче деталей... ;)
Комментариев нет:
Отправить комментарий