Я изучаю параллельное программирование на Java и пишу симулятор для Game of Life.
Вот что я думаю:
- Используйте int [] [] для хранения состояний ячеек
- разбить int [] [] на t сегментов и использовать t рабочих потоков
- Потоки t будут читать из своего сегмента, вычислять новые значения для всех ячеек в своем сегменте и обновлять ячейки.
- Как только они закончили расчет, они ждут у барьера, чтобы другие работники закончили
- при пересечении барьера основной поток обновит интерфейс.
- рабочие приступают к расчету следующего состояния.
Теперь на общих границах сегментов будет раздор. Если поток перезаписал состояние граничной ячейки до того, как его сосед прочитает предыдущее значение, вычисление соседа будет неверным.
Какие у меня варианты?
- Используйте callable вместо runnable и пусть рабочие потоки возвращают новое значение (вместо обновления самих сегментов). Основной поток может обновить матрицу после того, как барьер пройден. Эта опция включает в себя копирование результатов, возвращаемых рабочими потоками, в матрицу.
- Используйте два барьера. Рабочий поток делает копию пограничных ячеек из сегментов своих соседей и ждет у первого барьера. Как только этот барьер пройден, они продолжают вычислять следующие состояния и обновляют сегменты на месте. Затем они ждут у 2-го барьера. основной поток обновляет пользовательский интерфейс.
У меня вопрос, есть ли другой способ борьбы с конфликтом в граничных ячейках , который не связан с копированием данных или более эффективен , чем два вышеуказанных варианта? Может быть, использовать ReaderWriterLock, энергозависимую переменную или другой механизм синхронизации?
ОБНОВЛЕНИЕ: Пока что решение для двойной буферизации Питера является самым чистым. Но у меня есть вопрос. Поскольку эти два массива являются общими данными, и мы не используем синхронизацию (синхронизированный доступ или переменная переменная), не создаст ли это проблему видимости ? Могут ли несколько процессоров кэшировать значения массива и обновлять только часть массива с каждой итерацией? Тогда потоки получат устаревшие значения для граничных ячеек. Это возможно? Если нет, то почему. Если да, как мне это решить? Кажется, объявление двух массивов volatile не сделает их отдельные элементы volatile .