Состояние гонки в отдельном потоке

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

У меня есть основной цикл, создающий объект, тогда как этот объект имеет бесконечный цикл для обработки матрицы и выполнения действий с этой матрицей. Я вызываю эту функцию обработки в отдельном потоке и отсоединяю ее, поэтому она может обрабатывать матрицу несколько раз, в то время как основной цикл может просто ждать чего-то и ничего не делать.

Через некоторое время основной цикл получает новую матрицу, а я представлял это просто созданием новой матрицы и передачей этой новой матрицы в объект. Идея состоит в том, что из-за ожидания в течение нескольких секунд перед повторной обработкой бесконечного цикла 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);
}
}

К сожалению, происходит состояние гонки. Процесс и обновление имеют несколько шагов в заблокированной среде мьютекса, в то время как между этими шагами я печатаю данные на консоль. Я обнаружил, что и матрица перепутана, и буквы/цифры появляются параллельно, а не последовательно.

Любые идеи, почему это происходит?

С наилучшими пожеланиями и спасибо заранее

К вопросу отношения не имеет, но возможно ли, что вы забыли разблокировать мьютекс в updateMatrix?

Tobias Brösamle 01.03.2019 12:23

Поскольку это блокировка с ограниченной областью действия, мьютекс должен быть разблокирован при уничтожении шкафчика.

GFarmer 01.03.2019 12:25
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
2
98
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
    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 Мне нравятся блокировки с ограниченной областью действия, поскольку они обеспечивают безопасность раннего возврата / исключения. Я думаю, что блокировка с прицелом — правильный инструмент здесь, но, возможно, на самом деле правильная его прицельность (поэтому нет необходимости в какой-либо ручной разблокировке) была бы в конечном счете правильной.

Mike Vine 01.03.2019 12:36

@MikeVine ты лучший! locker.unlock() сделал это. Большое тебе спасибо!

GFarmer 01.03.2019 12:40

Другие вопросы по теме