std::thread join - виснет [закрыт]

134
27 января 2020, 22:10
Закрыт. Этот вопрос не по теме. Ответы на него в данный момент не принимаются.

Хотите улучшить этот вопрос? Переформулируйте вопрос, чтобы он соответствовал тематике «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 ?

Всем спасибо кто уделил внимание этому вопросу, закрыть его не имею возможности.

Answer 1

С чего вы взяли, что "тред кончился"??? Нет, конечно. Ваш join потому и "виснет", что тред не кончился и не кончится никогда.

  • Если _IsRun - глобальная переменная, т.е. доступна функции потока напрямую, то из-за того, что она не объявлена volatile, компилятор вправе генерировать код для функции потока в соответствии с логикой "если _IsRun изначально был true, то устраиваем бесконечный цикл, ибо поменяться _IsRun уже никак не может". На это поведение могут влиять барьеры памяти и инструкции, неявно генерирующие такие барьеры, но полный код функции потока вы не привели.

  • Если _IsRun - локальная переменная, то у вас функция потока захватывает переменные по значению, как вы сами явно попросили, т.е. у нее своя внутренняя копия переменной _IsRun. Изменение внешней _IsRun никак не влияет на внутреннюю копию, доступную функции потока.

Answer 2

Во первых нужно захватывать не по значению, а по ссылке. Вы в потоке просто копию _IsRun сделали. Копия изменения оригинала не видет. Во вторых std::atomic нужно. Иначе datarace. Если переменная не atomic (допустим даже компилятор ничего не оптимизировал), некоторое время после присваивания, разные ядра (соответственно разные потоки) могут видеть разные значения в переменной.

READ ALSO
Причем здесь лямбда?

Причем здесь лямбда?

Анонимные делегаты в Java 8 не являются лямбда-выражениями, тк

154
Не удается в фрагменте получить методы из интерфейса. Как это можно исправить?

Не удается в фрагменте получить методы из интерфейса. Как это можно исправить?

Почему при попытки получить методы из интерфейса, пишет Cannot resolve method 'isProduct()' и Cannot resolve method 'getMenuTitle()'ourMenuItemsя прописываю как ArrayList

148
настройка JNDI @Resource

настройка JNDI @Resource

в проекте (spring boot + embedded tomcat) я использую jar файл в котором есть класс

173