Я пытался найти похожую проблему, но не смог найти, либо моих знаний не хватило, чтобы распознать сходство.
У меня есть основной цикл, создающий объект, тогда как этот объект имеет бесконечный цикл для обработки матрицы и выполнения действий с этой матрицей. Я вызываю эту функцию обработки в отдельном потоке и отсоединяю ее, поэтому она может обрабатывать матрицу несколько раз, в то время как основной цикл может просто ждать чего-то и ничего не делать.
Через некоторое время основной цикл получает новую матрицу, а я представлял это просто созданием новой матрицы и передачей этой новой матрицы в объект. Идея состоит в том, что из-за ожидания в течение нескольких секунд перед повторной обработкой бесконечного цикла while функция обновления может заблокировать мьютекс, а мьютекс не (почти) часто блокируется.
Ниже я попытался написать минимальный пример.
class Test
{
public:
Test();
~Test();
void process(){
while(1){
boost::mutes::scoped_lock locker(mtx);
std::cout << "A" << std::endl;
// do stuff with Matrix
std::cout << "B" << std::endl;
mtx.unlock();
//wait for few microseconds
}
}
void updateMatrix(matrix MatrixNew){
boost::mutes::scoped_lock locker(mtx);
std::cout << "1" << std::endl;
Matrix = MatrixNew;
std::cout << "2" << std::endl;
}
private:
boost::mutex mtx;
matrix Matrix;
}
int main(){
Test test;
boost::thread thread_;
thread_ = boost::thread(&Test::process,boost::ref(test));
thread_.detach();
while(once_in_a_while){
Matrix MatrixNew;
test.updateMatrix(MatrixNew);
}
}
К сожалению, происходит состояние гонки. Процесс и обновление имеют несколько шагов в заблокированной среде мьютекса, в то время как между этими шагами я печатаю данные на консоль. Я обнаружил, что и матрица перепутана, и буквы/цифры появляются параллельно, а не последовательно.
Любые идеи, почему это происходит?
С наилучшими пожеланиями и спасибо заранее
Поскольку это блокировка с ограниченной областью действия, мьютекс должен быть разблокирован при уничтожении шкафчика.





while(1){
boost::mutes::scoped_lock locker(mtx);
std::cout << "A" << std::endl;
// do stuff with Matrix
std::cout << "B" << std::endl;
mtx.unlock();
//wait for few microseconds
}
Здесь вы вручную разблокируете mtx. Затем через некоторое время scoped_lock (называемый locker) также разблокирует мьютекс в своем деструкторе (что является точкой этого класса). Я не знаю, что требует гарантия boost::mutex, но разблокировать его больше раз, чем вы заблокировали, ни к чему хорошему не приведет.
Вместо
mtx.unlock(); вы предположительно хотите locker.unlock();
Изменить. Здесь рекомендуется избегать использования boost для этого и вместо этого использовать стандартный С++. threading является частью стандарта с C++11 (8 лет!), поэтому, по-видимому, все ваши инструменты теперь будут его поддерживать. Использование стандартизированного кода/инструментов дает лучшую документацию и лучшую помощь, поскольку они гораздо более известны. Я не сбиваю буст (многое из стандарта начиналось в бусте), но как только что-то ушло в стандарт, стоит серьезно задуматься об его использовании.
@DavideSpataro Мне нравятся блокировки с ограниченной областью действия, поскольку они обеспечивают безопасность раннего возврата / исключения. Я думаю, что блокировка с прицелом — правильный инструмент здесь, но, возможно, на самом деле правильная его прицельность (поэтому нет необходимости в какой-либо ручной разблокировке) была бы в конечном счете правильной.
@MikeVine ты лучший! locker.unlock() сделал это. Большое тебе спасибо!
К вопросу отношения не имеет, но возможно ли, что вы забыли разблокировать мьютекс в updateMatrix?