Хотите улучшить этот вопрос? Переформулируйте вопрос, чтобы он соответствовал тематике «Stack Overflow на русском».
Закрыт 10 месяцев назад.
Собственно проблема в полном умирании на операции join.
Вызывается из GUI, обработчик WM_COMMAND
class Test1
{
private:
bool _IsRun;
// volatile bool _IsRun; // без изменений
// std::atomic<bool> _IsRun; // без изменений
std::thread _thm;
void Test();
public:
Test1() : _IsRun(false) {}
~Test1() {}
...
};
void Test1::Test()
{
if (_IsRun)
{
_IsRun = false;
if (_thm.joinable())
_thm.join();
return;
}
_IsRun = true;
std::thread thw
{
[=]()
{
while (_IsRun)
{
....
}
_IsRun = false;
}
};
_thm = move(thw);
// std::swap(_thm, thw);
}
Понимаю что что-то делаю не так, но не соображу что.
В detach() режиме работает как часы.. без _thm.joinable() в блоке if естественно ..
Upd:
Проблема все же найдена, поскольку в создаваемом потоке присутствуют long-time операции, то помогла проверка _IsRun перед каждой из них. Общее впечатление, что если поток "задумался" на довольно продолжительное время во время ожидания (join) в GUI, то из этого состояния GUI просто не выйти.. При прохождении в отладке всего блока потока во время join ошибок нет и всё завершается как запланированно. Особенности w10 ?
Всем спасибо кто уделил внимание этому вопросу, закрыть его не имею возможности.
С чего вы взяли, что "тред кончился"??? Нет, конечно. Ваш join потому и "виснет", что тред не кончился и не кончится никогда.
Если _IsRun - глобальная переменная, т.е. доступна функции потока напрямую, то из-за того, что она не объявлена volatile, компилятор вправе генерировать код для функции потока в соответствии с логикой "если _IsRun изначально был true, то устраиваем бесконечный цикл, ибо поменяться _IsRun уже никак не может". На это поведение могут влиять барьеры памяти и инструкции, неявно генерирующие такие барьеры, но полный код функции потока вы не привели.
Если _IsRun - локальная переменная, то у вас функция потока захватывает переменные по значению, как вы сами явно попросили, т.е. у нее своя внутренняя копия переменной _IsRun. Изменение внешней _IsRun никак не влияет на внутреннюю копию, доступную функции потока.
Во первых нужно захватывать не по значению, а по ссылке. Вы в потоке просто копию _IsRun сделали. Копия изменения оригинала не видет. Во вторых std::atomic нужно. Иначе datarace. Если переменная не atomic (допустим даже компилятор ничего не оптимизировал), некоторое время после присваивания, разные ядра (соответственно разные потоки) могут видеть разные значения в переменной.
Продвижение своими сайтами как стратегия роста и независимости