Я пишу эмулятор старого компьютера на Java / Swing, и мне кажется, что я обнаружил проблему с дизайном, которая у меня возникла. Как ни странно это приложение, я подозреваю, что кто-то найдет «образец» этой проблемы.
Я должен добавить, что я все еще новичок в ООП, графических интерфейсах и шаблонах проектирования.
Машина имеет поток GUI (консоль) - с кнопками и переключателями, а также поток модели (ЦП), с которым консоль взаимодействует, чтобы события консоли изменяли состояние ЦП. Консоль, конечно, управляется событиями из очереди событий AWT. Консоль обменивается данными с процессором, помещая в очередь сообщения в приоритетной очереди блокировки, которую получает процессор. Таким образом, ЦП также структурирован как цикл обработки событий. Пока все хорошо.
Проблема в том, что, когда вы нажимаете START на консоли, вы хотите, чтобы процессор начал выполнять любую программу, которая находится в его памяти. Он по-прежнему должен реагировать на броски переключателей и нажатия кнопок (например, STOP) с консоли, но в основном ему нужно сидеть и вращаться в цикле fetch-decode-execute инструкции.
И даже это некоторое время не было проблематично: у меня был метод с именем Cycle () , который выполнял бы один конкретный «цикл» текущей инструкции и затем возвращал, чтобы его немедленно пересылали для выполнения следующий цикл. Я поместил вызов Cycle () в цикл выполнения ЦП и опрашивал очередь сообщений после каждого цикла. Если процессор был остановлен, цикл выполнения просто будет ждать в очереди сообщений.
Теперь: я выполняю инструкции ввода / вывода, например, Читать карту. Для одного из циклов необходимо отправить запрос данных на рассматриваемое периферийное устройство (само реализованное в виде графического интерфейса пользователя / модели, работающей в отдельных потоках), а затем ждать данных прибывать. Это полностью нарушает представление о том, что процессор является простым циклом обработки событий, который получает сообщения и воздействует на них, не вызывая блокировку в процессе. Этот новый цикл будет блокироваться. И если оператор не загрузил колоду карт в считыватель, он может заблокироваться на длительное время.
Я думал о выделении цикла инструкции fetch-decode-execute в отдельный «рабочий» поток, но я не думаю, что он подходит, так как рабочие потоки (насколько я понимаю) предназначены для асинхронной работы до завершения , и не продолжайте взаимодействовать с их родительским потоком во время работы. (На самом деле, я не могу понять, почему «рабочий поток» должен когда-либо завершаться.) Кроме того, в настоящее время не требуется синхронизация, когда циклу требуется доступ к данным, которые могут быть одновременно изменены в результате нажатий клавиш консоли.
Так как мне скомбинировать обработку, "управляемую событиями", с традиционным пакетным процессом, который должен явно ждать сообщений перед продолжением?