1. Заголовок или название темы должно быть информативным ! 2. Все тексты фрагментов программ должны помещаться в теги [code] ... [/code] или [code=pas] ... [/code]. 3. Прежде чем задавать вопрос, см. "FAQ" и используйте ПОИСК ! 4.НЕ используйте форум для личного общения! 5. Самое главное - это раздел теоретический, т.е. никаких задач и программ (за исключением небольших фрагментов) - для этого есть отдельный раздел!
Какая-то странная тема. С одной стороны непростые требования - реальное время и большие массивы (но при этом не решается задача управления внешним устройством), с другой - неготовность к реализации.
Поэтому, думаю, что решение в пересмотре алгоритмов и структур данных. Как вариант - распараллеливание вычислений. Работа в нескольких потоках. Но тут моего опыта очень мало.
Для меня тема совсем не странная, и многое что вы мне подсказали, да и OCTAGRAM тоже, очень многое объясняет и хотя положительного результата пока нет жизненный опыт подсказывает, что раньше или позже выход найдётся, например сейчас я пытаюсь применить RamDisk (интересно что лет 20 я уже применял его для других задач) так что большое спасибо за подсказку, возможно это позволит устранить некоторые ограничения...
Можете объяснить более подробно что вы имели ввиду под: ... не решается задача управления внешним устройством? ... неготовность к реализации? ... распараллеливание вычислений? ... Работа в нескольких потоках? ... или отправить меня... к первоисточникам)
... распараллеливание вычислений? ... Работа в нескольких потоках? ... или отправить меня... к первоисточникам)
Имеются в виду многопроцессорные или многоядерные системы, где можно параллельно делать несколько вычислений и успевать то, что не успевается в одном потоке. Если вы работаете в DOS, это вам едва ли под силу. Планировщики, переключающие потоки на одном ядре, ещё можно встретить, но вот чтоб именно параллельно выполнялось — едва ли. В принципе, конечно, осуществимо. Несколько лет назад Дмитрий Константинович Завалишин написал с нуля Фантом ОС, а, значит, в том числе разобрался, как посылать межпроцессорное прерывание (IPI, Inter-Processor Interrupt), чтоб запускать потоки планировщика на других ядрах и как реализовать стандартные примитивы синхронизации, и написал в Хабрахабр.
Для параллельности на голых досках сейчас, на мой взгляд самое доступное решение — это GNAT (но архитектура ARM). Там адский рантайм становится одновременно и как бы операционной системой. Языковые возможности многозадачности полностью поддерживаются сопутствующим планировщиком, и по сравнению с Делфи на порядок удобнее даже для не сильно владеющего теорией человека.
Видел однажды, как бывший коллега в наследнике TThread понаобъявлял публичных методов и ходил в них как изнутри задачи, так и снаружи без синхронизации, и, конечно, всё это регулярно глючило. Корректно реализованные мониторы вообще очень долго не были доступны для разработчиков на Делфи (Windows Event не является корректной заменой условной переменной). Это только Gurock переписал на Delphi, а потом ещё, как в Windows Vista мониторы появились в API, это стало встроенной возможностью в Delphi (кажется, это была 2009). Соответственно, опыта корректной многозадачной разработки в Делфи-сообществе просто нет.
Адским инструментарием task/protected несколько сложнее делать ошибки. Вход/выход из секций чтения/записи, пульсации условных переменных и прочее создаются транслятором автоматически.
Сообщение отредактировано: OCTAGRAM -
--------------------
If you want to get to the top, you have to start at the bottom
А это смотря какой. Если для голых досок, но с многозадачностью — тогда эту клавиатуру нужно ещё подключить суметь. Я так понимаю, там датчики всякие и порты ввода/вывода под рукой, а клавиатуру, например, через USB придётся читать.
Если GNAT для Windows, запущенный под DOS одним из расширителей, то расширитель сводит WinAPI к DOS API. Как там через несколько слоёв (в Windows даже и без эмуляции юникодный ввод/вывод весёлый) всё будет проходить, не знаю, и именно поэтому я бы взял Win32Ada и делал прямые вызовы к консольному WinAPI. А дальше ответ на ваш вопрос зависит от реализации расширителя DOS. Какие-то вроде бы умеют в Юникоде давать ответ на ReadConsoleW.
В принципе, есть возможность стандартные текстовые потоки ввода/вывода читать/писать как бинарные. Для этого берётся Ada.Text_IO.Standard_Input и подаётся на вход Ada.Text_IO.Text_Streams.Stream, а дальше с ним идёт работа как с потоком.
Пример чтения файла средствами двоичных потоков(Показать/Скрыть)
function Get_File_Contents (File_Name : String) return String is F : Ada.Streams.Stream_IO.File_Type; begin Ada.Streams.Stream_IO.Open (F, Ada.Streams.Stream_IO.In_File, File_Name, "Text_Translation=No,WCEM=8,encoding=utf8,shared=no");
return Result : String (1 .. Natural (Ada.Streams.Stream_IO.Size (F))) do String'Read (Ada.Streams.Stream_IO.Stream (F), Result); Ada.Streams.Stream_IO.Close (F); end return;
exception when others => Ada.Streams.Stream_IO.Close (F); raise; end Get_File_Contents;
Здесь собственно ядро — это String'Read, но для него нужно заранее знать размер, в данном примере это заранее известный размер файла. Есть ещё функция String'Input, она двоично считает длину строки в системном endian (на x86 сначала самый младший байт), потом саму строку и вернёт как функцию. Как правило, такое поведение мало, где нужно, но вот Character'Input (S) вполне полезен. И есть парные им атрибуты 'Write (не пишет дискриминанты, а только содержимое) и 'Output (сначала дискриминанты, потом содержимое). Атрибуты такие есть у многих типов. Integer'Input (S) прочитает 4хбайтовое число в системном endian. Если тип record объявить, у него такие атрибуты автоматически появятся.
Но я вот опасаюсь, что эти функции уже могут работать поверх какого-то слоя, который делает UTF-8 поверх консоли Windows (где-нибудь в MinGW), и как этот слой ведёт себя на расширителе, неизвестно.
Есть ещё довольно старый GNAT 3.15p для DOS (не WinAPI), можно найти, если видновый на расширителях не будет работать. Но там по API я не знаю, как. По крайней мере, ассемблерным шаблоном прерывания-то можно вызывать из защищённого режима, и наверняка в библиотеке GNAT найдётся высокоуровневая обёртка для вызова прерываний. Соответственно, и опрашивать через прерывания DOS.
Ещё такой вариант. В расширителях DOS (как с эмуляцией WinAPI, так и без), я так понимаю, нет страничной адресации, и буфер клавиатуры можно читать напрямую из памяти, а он где-то в первых байтах. Тогда можно под него record объявить с его структурой, переменную объявить с pragma Import и указать адрес в физической памяти.
Какого-то единого модуля Crt для GNAT мне неизвестно. GNATCOLL.Terminal умеет цвета в консолях Windows и Linux переключать, а опросить клавиатуру — не может, там вообще нет ввода. Ближайший аналог TextTools разрабатывается, главным образом, на Linux. Если у них там действительно ncurses в основании, то гипотетически можно на Windows взять pdcurses, у которого такой же API, и тогда функцией KeyPress узнавать, нажата ли какая-то клавиша. Но понятно, что проще взять Win32Ada и делать вызовы напрямую, чем портировать TextTools.
Сообщение отредактировано: OCTAGRAM -
--------------------
If you want to get to the top, you have to start at the bottom
Почитал руководство по ADA)... пока мне сложно оценить будет ли от него польза, более 400 страниц не одолеть за один вечер... и даже за 10. отсюда вопрос могу ли я вас попросить (поскольку как я понял хорошо знаете тему) запустить на ADA кусочек программы (Pascal строк 10) связанный с опросом буфера клавиатуры и работающий в реальном времени? Если о результате невозможно будет сказать какая программа его выводит, значит в принципе можно двигаться дальше, т.е. добавить в него кусочек кода для определения девиации времени (ещё строк 20) и если результат будет в пределах 1-2% можно пробовать перебивать весь код целиком.
Я тут ещё повспоминал, и довспомался до прерываний.
Во-первых, есть аппаратное прерывание клавиатуры, но его нетривиально обрабатывать. В принципе, я писал обработчик на Turbo Pascal, это было нужно, чтоб одновременно нажатые клавиши в танках знать. Массив Boolean был. Но там нужно с портами ввода/вывода аккуратно работать, на прерывания маску ставить и снимать, иначе клавиатура отваливается. Из защищённого режима такое перехватить — дополнительные сложности.
А вот есть другое прерывание, которое вызывается ДОСовским обработчиком прерывания клавиатуры после трансляции кода клавиши в символ (то есть, уже русифицированный). Вот можно это прерывание перехватить, и узнавать о нажатии мгновенно.
Из защищённого режима DOS можно взаимодействовать с реальным режимом. Там в DPMI есть всякие вызовы. Есть вызов кода в реальном режиме по известному адресу. Можно, наоборот, попросить DPMI выделить в реальном режиме процедуру, вызов которой будет транслироваться в вызов процедуры в защищённом режиме. Но для прерывания это вроде бы маловато, потому что при вызове прерывания в стек кладётся не только адрес следующей инструкции после возврата, но и состояние флагов, и возврат делается инструкцией iret (Interrupt RETurn) или инструкциями popf, retf. Это решаемо, можно после выделения в реальном режиме процедуры попросить ещё DPMI выделить память в реальном режиме, и вписать туда по шаблону инструкции, которые вызовут ранее выделенную процедуру в реальном режиме. И адрес этой последней памяти записать в таблицу прерываний, сохранив прошлое значение. В прошлое значение, как я понимаю, тоже просто так перейти не получится из-за того, что прошлый обработчик будет пытаться освободить флаги со стека, а обычные процедуры так не делают. Тут тоже можно коменсировать это перемычкой в реальном режиме. И так получается, что программа защищённого режима вклинивается в цепочку обработчиков прерываний в реальном режиме.
Возможно, в DPMI уже есть поддержка замены обработчиков прерываний, и получится обойтись без перемычек.
Сообщение отредактировано: OCTAGRAM -
--------------------
If you want to get to the top, you have to start at the bottom