Котлин, проблема гонки

Соответствующий код здесь

По сути, у нас есть два потока, один из которых ведет рендеринг, который продолжает вызывать display() и другой, который заботится о пользовательских вводах, вызывая соответствующее событие мыши или ключа соответственно

Поля полюса и объекта – это не что иное, как вспомогательные классы для облегчения обработки матрицы относительно камеры и объекта (ов).

Их методы называются как из display() и из методов ввода пользователя.

display() вызывает как viewpole.calcMatrix() и objectpole.calcMatrix() то время как входной поток вызывает их косвенно, например basicLighting.mouseDragged() -> objectpole.mouseDragged() -> rotateView() -> calcMatrix()

Состояние гонки начало появляться, когда я начал использовать объекты пула для уменьшения давления GC в конкретных сценариях. Я проверил десятки раз, каждый объект используется только один раз (кроме того, when ).

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

Исследуя, я узнал, используя простой println , например, что Viewpole.calcMatrix() иногда вызывался, пока другой вызов не завершил его полностью.

Добавление @Synchronized на каждом calcMatrix() (viewpole и objectpole) значительно уменьшило его, я бы сказал, 80/90%.

Но все же, несколько раз, я испытываю расовое состояние. Я попытался synchronize(lock){} также каждый вызов из пользовательского потока ввода, как здесь :

 val lock = Any() override fun mousePressed(e: MouseEvent) { synchronized(lock) { viewPole.mousePressed(e) objectPole.mousePressed(e) } } 

Это не помогло.

Что я делаю не так? И какой правильный способ реализовать синхронизацию для моего случая? То есть два потока, вызывающих один и тот же класс.

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

Что вы делаете неправильно, трудно сказать, не пересматривая весь ваш код. Но вот несколько советов: / viewPole.calcMatrix () возвращает ссылку на mat4_B. В display () эта ссылка используется за пределами синхронизированного блока. Таким образом, mat4_B потенциально может быть изменен одновременно при использовании display () / viewPole.calcMatrix (), а objectPole.calcMatrix () вызывается в отдельных синхронизированных блоках. Таким образом, матрица viewPole может быть основана на другом состоянии, а затем на объектной матрице. Я не могу сказать, является ли это проблемой для вашего случая использования.

Подход должен состоять в том, чтобы: / уменьшить общее состояние как можно больше (т.е. путем передачи копий) / выборки всех данных в одной, атомной (синхронной) операции