Я пытаюсь включить потоки в свой проект, но у меня возникает проблема, когда использование только одного рабочего потока приводит к тому, что он постоянно "засыпает".Возможно, у меня есть состояние гонки, но я просто не могу этого заметить.
Мой PeriodicThreads
объект поддерживает коллекцию потоков.Как только PeriodicThreads::exec_threads()
был вызван, потоки уведомляются, пробуждаются и выполняют свою задачу.После этого они снова засыпают.
Функция такого рабочего потока:
void PeriodicThreads::threadWork(size_t threadId){
//not really used, but need to decalre to use conditional_variable:
std::mutex mutex;
std::unique_lock<std::mutex> lck(mutex);
while (true){
// wait until told to start working on a task:
while (_thread_shouldWork[threadId] == false){
_threads_startSignal.wait(lck);
}
thread_iteration(threadId); //virtual function
_thread_shouldWork[threadId] = false; //vector of flags
_thread_doneSignal.notify_all();
}//end while(true) - run until terminated externally or this whole obj is deleted
}
Как видите, каждый поток отслеживает свою собственную запись в векторе флагов, икак только он увидит, что его флаг истинен - выполняет задачу, затем сбрасывает ее флаг.
Вот функция, которая может пробудить все потоки:
std::atomic_bool _threadsWorking =false;
//blocks the current thread until all worker threads have completed:
void PeriodicThreads::exec_threads(){
if(_threadsWorking ){
throw std::runtime_error("you requested exec_threads(), but threads haven't yet finished executing the previous task!");
}
_threadsWorking = true;//NOTICE: doing this after the exception check.
//tell all threads to unpause by setting their flags to 'true'
std::fill(_thread_shouldWork.begin(), _thread_shouldWork.end(), true);
_threads_startSignal.notify_all();
//wait for threads to complete:
std::mutex mutex;
std::unique_lock<std::mutex> lck(mutex); //lock & mutex are not really used.
auto isContinueWaiting = [&]()->bool{
bool threadsWorking = false;
for (size_t i=0; i<_thread_shouldWork.size(); ++i){
threadsWorking |= _thread_shouldWork[i];
}
return threadsWorking;
};
while (isContinueWaiting()){
_thread_doneSignal.wait(lck);
}
_threadsWorking = false;//set atomic to false
}
Вызов exec_threads()
отлично работает длянесколько сотен или в редких случаях несколько тысяч последовательных итераций.Вызовы происходят из цикла while
основного потока.Его рабочий поток обрабатывает задачу, сбрасывает ее флаг и переходит в спящий режим до следующего exec_threads()
и т. Д.
Однако через некоторое время программа переходит в «спящий режим» и кажется,чтобы сделать паузу, но не вылетает.
Во время такой "гибернации" установка точки останова на любом while-loop
моих condition_variables никогда не приводит к срабатыванию этой точки останова.
СуществоПодлый, я создал свой собственный ветвь проверки (параллельно main
) и наблюдаю за моим PeriodicThreads
объектом.Когда он входит в режим гибернации, мой контрольный поток продолжает выводить на консоль сообщение о том, что в настоящий момент ни один из потоков не запущен (для _threadsWorking
atomic из PeriodicThreads
постоянно установлено значение false).Тем не менее, во время других испытаний атом остается true
, как только начинается эта «проблема гибернации».
Странно то, что если я заставлю PeriodicThreads::run_thread
спать не менее 10 микросекунд перед сбросом егофлаг, все работает как обычно, и никакой "гибернации" не происходит.В противном случае, если мы позволим потоку выполнить его задачу очень быстро, это может вызвать всю эту проблему.
Я завернул каждый condition_variable
в цикл while, чтобы предотвратить случайные пробуждения от запуска перехода, и ситуацию, в которой notify_all
вызывается до того, как .wait()
вызывается на нем. Ссылка
Обратите внимание, это происходит, даже если у меня есть только 1 рабочий поток
В чем может быть причина?
Редактировать
Отмена этих векторных флагов и просто тестирование на одном atomic_bool
с 1 рабочим потоком все еще показывает ту же проблему.