Как правильно завершить тему? - PullRequest
1 голос
/ 06 апреля 2020

Моя основная программа создает поток. Этот поток инициализирует некоторые данные, затем вводит 'while' l oop и работает до тех пор, пока основная программа не установит управляющую переменную в значение 'false'. Затем он вызывает join (), который бесконечно блокирует весь код.

bool m_ThreadMayRun;

void main(){
   thread mythread = thread(&ThreadFunction);
   //do stuff
   m_ThreadMayRun = false;
   mythread.join(); // this blocks endlessly even when I ask 'joinable' before
}

void ThreadFunction{
   initdata();
   m_ThreadMayRun=true;
   while(m_ThreadMayRun){
   //do stuff that can be / has to be done for ever
   }
   deinitdata();
}
  • Я что-то здесь упускаю?
  • Что было бы правильным решением для создания l oop выйти из основного потока?
  • Нужно ли вообще вызывать join?

Спасибо за помощь

Ответы [ 2 ]

2 голосов
/ 06 апреля 2020

Проблема в том, что доступ к bool m_ThreadMayRun; не синхронизирован, и в соответствии с правилами C ++ каждый поток может предполагать, что он не изменяется между потоками. Таким образом, вы получите расу (форма неопределенного поведения).

Чтобы прояснить намерение, сделайте его atomic.

std::atomic<bool> m_ThreadMayRun;

С этим каждым грузом / хранилищем m_ThreadMayRun становится ограничением памяти, которое не только синхронизирует свое собственное значение, но и делает другую работу , выполняемую потоком видимой, благодаря семантике получения / освобождения атома c загрузка / сохранение.

Хотя возможна небольшая гонка между m_ThreadMayRun = true в потоке и настройкой m_ThreadMayRun = false. Любой из них может быть выполнен первым, что иногда приводит к нежелательным результатам. Чтобы избежать этого, инициализируйте его как true перед запуском потока.

std::atomic<bool> m_ThreadMayRun;

void main(){
   m_ThreadMayRun = true;
   thread mythread(&ThreadFunction);
   //do stuff
   m_ThreadMayRun = false;
   mythread.join(); // this blocks endlessly even when I ask 'joinable' before
}

void ThreadFunction{
   initdata();
   while(m_ThreadMayRun){
   //do stuff that can be / has to be done for ever
   }
   deinitdata();
}

Для получения дополнительной информации об ограждениях памяти и семантике получения / выпуска см. Следующие превосходные ресурсы: книга " C ++ параллелизм в действии " и atomic<> оружия Херба Саттера разговора.

2 голосов
/ 06 апреля 2020

У вас есть условие гонки для двух потоков, записывающих в m_ThreadMayRun. Посмотрим, что произойдет, если сначала основной поток выполнит m_ThreadMayRun = false;, а затем поток, который вы spwaned, выполнит m_ThreadMayRun = true;, тогда у вас будет бесконечное число l oop. Тем не менее, строго говоря, эта аргументация не имеет значения, потому что когда у вас есть состояние гонки, ваш код имеет неопределенное поведение.

Я что-то здесь упускаю?

Вам необходимо синхронизировать доступ к m_ThreadMayRun, указав std::atomic<bool> или std::mutex и убедитесь, что что m_ThreadMayRun = false выполняется после m_ThreadMayRun = true;.

PS Для этой ситуации лучше использовать std::condition_variable.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...