C++, параллелизм и введение в автоматное программирование в SimInTech

Поводом для написания статьи послужило не очень приятное для меня событие: модератор Хабра убрал теги – «С++» и «Параллельное программирование» из моей крайней статьи [1]. Этому предшествовало сообщение пользователя, который по его словам не заметил в статье ни С++, ни параллелизма и поспешил об этом известить весь свет. На самом деле он, скорее всего, просмотрел статью по диагонали и попросту «не врубился». Другим объяснить сей казус сложно. Я объяснил причины его заблуждения, но это не было принято во внимание. В ответ – тишина и, более того, пошли у него на поводу.

А до этого, но тоже в контексте рассматриваемой статьи (теперь все это складывается в один пазл), произошло еще одно событие.  Другой пользователь, решивший, видимо, поддержать автора, выразил благодарность, но допустил не очень лестные высказывания в адрес специалистов Бауманки. Не то, чтобы я с ним был во всем согласен, но поскольку на асфальте розы не растут, то в чем-то он был все же прав.

Но дело даже не в содержании постов. Если раньше управлять спорными постами доверялось автору, то теперь модератор решил взять на себя это право. Может, у нас месячник усиленной модерации? Но только в чем причины столь сильного недоверия автору? Ведь, модератор явно не очень вникал в суть проблемы и причины появления подобных постов. Логично было бы предоставить, как и ранее, автору решать вопросы, связанные с содержанием его же статей. Последнее сообщение, хотя и содержало критику, но в целом не нарушало правила сообщества. Хотя, обобщать на всю Бауманку, конечно, не стоило бы.

Однако, оставим пересуды в стороне, а поговорим про С++,  параллелизм и об автоматном программировании. А тут без ВКПа и, как ни странно, без SimInTech не обойтись. Так уж сложилось, что есть, что сказать на обозначенные темы и для нее.

1. С++ и ВКПа

Автором только  на Хабре написано более двух десятков статьей на тему ВКПа. И если не в каждой, то в большинстве из них подчеркивается, что ее основой является С++. Говоря ВКПа, мы должны подразумевать С++ ровно также, как мы это делаем в контексте упоминания тех же Visual Studio или Qt. Для ВКПа С++ не просто язык, на котором она разработана, но и ее внутренний язык программирования (ЯП). И если, например, MATLAB  или SimInTech имеют свои внутренние ЯП, то здесь им является именно С++.

Иметь С++ в двух ипостасях, языка проектирования самой среды и ее внутреннего ЯП,  весьма удобно, т.к. не требует специализированного языка программирования среды. Создание последнего — сама по себе задача весьма сложная и трудоемкая.  В ВКПа же есть все то, что есть или будет в С++. На текущий момент сюда подключаются также возможности библиотеки Qt и ее средств проектирования (до этого – Visual Studio).

Безусловно, на уровне среды также есть потребность в неком языке программирования. Во многих случаях он позволяет быстро сделать пусть некий набросок решения или реализовать простые функции, не погружаясь в С++. И по существу подобные возможности также можно считать расширением С++. В рамках самого С++ они, во-первых, вылились в создание шаблона описания автоматов в форме таблиц переходов и формирование новой алгоритмической модели.

Активные автоматные объекты качественно расширяют С++. Могу ошибаться, но, думаю, пока в стандартах С++ на эту тему нет и речи. В него внедрили другое: так называемое, многопоточное параллельное программирование, корутины и им подобное.  Все это по большей части вызывает только большое сожаление, т.к. добавленные «языковые конструкции» не отвечают теории и только усложняют язык, создавая ему проблемы.

Если говорить о надстройке над С++, то в ВКПа он был расширен диалоговыми средствами реализации простых автоматных алгоритмов. Именно такая ситуация была показана в рамках «забаненной» статьи. Там была создана модель управления нагревателем без привлечения мощи языка С++. Получилось проще, быстрее  и под силу тем, кто не знает С++, но должен хоть немного понимать в автоматах.  Причем речь идет не о диаграммах Харелла, а о более простых и строгих – классических автоматах.

Покажем разницу двух подходов, приведя реализацию блоков проекта «Нагреватель» из упомянутой выше статьи на С++. Первый листинг (листинг. 1) – автомат управления, второй – простейший переключатель (листинг 2).  По технологии проектирования автоматов на С++ требуется внести  определенные дополнения в код их реализации, что не так уж сложно. Сюда, во-первых, входит создание необходимых ссылок на переменные среды и указателей на другие процессы, используя стандартный метод автоматного класса — FCreationOfLinksForVariables. Во-вторых, добавить в автомат петлю при начальном состоянии, нагруженную предикатом и действием (см. листинги). В процессе работы только после создания ссылок автомат выполняется переход в те или иные рабочие состояния автомата. Заметим, что эти же действия на уровне диалогов среды (см. применение диалога FAutomaton в [1]) реализуются средой автоматически. Потому-то автомат там и выглядит проще.

Листинг 1. Код блока управления нагревателем
#include "lfsaappl.h"  class FHeatingControl :     public LFsaAppl { public:     LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF)return new FHeatingControl(nameFsa, pCVarFsaLibrary); }     bool FCreationOfLinksForVariables();     FHeatingControl(string strNam, CVarFsaLibrary *pCVFL);     virtual ~FHeatingControl(void) { }     CVar    *pVarStrT;// имя переменной температуры     CVar    *pVarStrT_set;// имя переменной уставки температуры     CVar  *pVarCoolingDelay;   // время охлаждения     CVar    *pVarHeatingDelay;   // время нагрева protected:     int x1(); int x2(); int x12();     void y1(); void y2(); void y12();     CVar*pVarT;// температура воды     CVar*pVarT_set;// уставка температуры };  #include "stdafx.h" #include "FHeatingControl.h" static LArc TBL_HeatingControl[] = {     LArc("st","st","^x12","y12"),     LArc("st","off","x12","y2"),     LArc("on","off","^x2","y2"),     LArc("on","off","^x1","y2"),     LArc("off","on","x1^x2","y1"),     LArc() };  FHeatingControl::FHeatingControl(string strNam, CVarFsaLibrary *pCVFL):     LFsaAppl(TBL_HeatingControl, strNam, nullptr, pCVFL) { }  bool FHeatingControl::FCreationOfLinksForVariables() {      pVarCoolingDelay = CreateLocVar("dCoolingDelay", CLocVar::vtInteger, "cooling time");     pVarHeatingDelay = CreateLocVar("dHeatingDelay", CLocVar::vtInteger, "heating time");      pVarStrT = CreateLocVar("strNameT", CLocVar::vtString, "current temperature");     string str = pVarStrT->strGetDataSrc();     if (str != "") { pVarT = pTAppCore->GetAddressVar(pVarStrT->strGetDataSrc().c_str(), this); }      pVarStrT_set = CreateLocVar("strNameT_set", CLocVar::vtString, "temperature setpoint");     str = pVarStrT_set->strGetDataSrc();     if (str != "") { pVarT_set = pTAppCore->GetAddressVar(pVarStrT_set->strGetDataSrc().c_str(), this); }     return true; } // predicates int FHeatingControl::x1() { return pVarT->GetDataSrc() <= pVarT_set->GetDataSrc(); } int FHeatingControl::x2() { return FIsActiveParDelay(); } int FHeatingControl::x12() { return pVarT != nullptr && pVarT_set; } // action void FHeatingControl::y1() { FCreateParDelay(pVarCoolingDelay->GetDataSrc()); } void FHeatingControl::y2() { FCreateParDelay(pVarHeatingDelay->GetDataSrc()); } void FHeatingControl::y12() { FInit(); } 

Листинг 2. Код переключателя
#include "lfsaappl.h"  class FHeatingSwitch :     public LFsaAppl { public:     LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF)return new FHeatingSwitch(nameFsa, pCVarFsaLibrary); }     bool FCreationOfLinksForVariables();     FHeatingSwitch(string strNam, CVarFsaLibrary *pCVFL);     virtual ~FHeatingSwitch(void) { }     CVar    *pVarStrInput;// имя входной переменной     CVar    *pVarStrInput1;// имя входной переменной     CVar    *pVarStrInput2;// имя входной переменной     CVar    *pVarStrOutput;// имя выходной переменной protected:     int x1(); int x12();     void y1(); void y2(); void y12();     CVar    *pVarInput;// адрес входной переменной     CVar    *pVarInput1;// адрес входной переменной     CVar    *pVarInput2;// адрес входной переменной     CVar    *pVarOutput;// адрес выходной переменной };  #include "stdafx.h" #include "FHeatingSwith.h" static LArc TBL_HeatingSwitch[] = {     LArc("st","st","^x12", "y12"),     LArc("st","s1","x12","--"),     LArc("s1","s1","^x1","y2"),     LArc("s1","s1","x1", "y1"),     LArc() };  FHeatingSwitch::FHeatingSwitch(string strNam, CVarFsaLibrary *pCVFL):     LFsaAppl(TBL_HeatingSwitch, strNam, nullptr, pCVFL) { }  bool FHeatingSwitch::FCreationOfLinksForVariables() {      pVarStrInput = CreateLocVar("strNameInput", CLocVar::vtString, "input");     string str = pVarStrInput->strGetDataSrc();     if (str != "") { pVarInput = pTAppCore->GetAddressVar(pVarStrInput->strGetDataSrc().c_str(), this); }     pVarStrInput1 = CreateLocVar("strNameInput1", CLocVar::vtString, "input1");     str = pVarStrInput1->strGetDataSrc();     if (str != "") { pVarInput1 = pTAppCore->GetAddressVar(pVarStrInput1->strGetDataSrc().c_str(), this); }     pVarStrInput2 = CreateLocVar("strNameInput2", CLocVar::vtString, "input2");     str = pVarStrInput2->strGetDataSrc();     if (str != "") { pVarInput2 = pTAppCore->GetAddressVar(pVarStrInput2->strGetDataSrc().c_str(), this); }     pVarStrOutput = CreateLocVar("strNameOutput", CLocVar::vtString, "output");     str = pVarStrOutput->strGetDataSrc();     if (str != "") { pVarOutput = pTAppCore->GetAddressVar(pVarStrOutput->strGetDataSrc().c_str(), this); }     return true; } // predicates int FHeatingSwitch::x1() { return int(pVarInput->GetDataSrc()); } int FHeatingSwitch::x12() { return pVarInput != nullptr && pVarInput1 && pVarInput2 && pVarOutput; } // action void FHeatingSwitch::y1() { pVarOutput->SetDataSrc(nullptr, pVarInput1->GetDataSrc()); } void FHeatingSwitch::y2() { pVarOutput->SetDataSrc(nullptr, pVarInput2->GetDataSrc()); } void FHeatingSwitch::y12() { FInit(); } 

Код на С++ позволяет, создавать автоматы любой сложности (или, по-другому, активные объекты), которые легко превращаются в элементы библиотек.  Включенные в библиотеки подобные активные объекты можно многократно использовать в любом проекте среды ВКПа.

2. О параллелизме ВКПа

«Уж сколько раз твердили миру», что сеть автоматов — параллельная модель, в которой каждый автомат — параллельный процесс, синхронизация которых реализуется путем обмена информацией о состояниях (подробнее о параллелизме автоматов см. [3]). В автоматной сети фактически нет проблем, порождаемых типовым подходом к реализации параллелизма.

Если же мы вернемся к проекту нагревателя, то только прикладных, т.е. относящихся к самому проекту, параллельных автоматов пять. Это рассмотренные выше два автомата, еще два автомата управления индикацией и автомат-интегратор (см. также [1]). Необходимо еще учесть динамически порождаемые параллельные процессы задержек. С учетом диалогов управления средой в нашем проекте в общей сумме одномоментно крутится до двадцати параллельных автоматов. И после этого кто-то еще смеет может утверждать, что в проекте нет параллелизма!? Ну, а если нужно знать точное число параллельных процессов, то их отражает стандартный диалог автоматных пространств. Можно о них получить и более детальную информацию, открыв диалог автоматных переменных. Здесь отражается информация о библиотеке и ее элементе, от которого порожден процесс, и его имя, как процесса. Еще один параллельный диалог позволят управлять локальными переменными процесса. Это ли не в целом параллельное решение, заслуживающее соответствующего тега?

Модель параллельных процессов ВКПа — пример совершенно иного подхода к созданию параллельных решений. В ней все проблемы современных параллельных решений — гонки, тупики, проблемы синхронизация и т.п. решаются  на уровне модели процессов, где, повторимся, каждый автомат — это математическая модель отдельного процесса, а все они вместе – формальная модель параллельного множества процессов. Они «по щелчку» синхронизируют свою работу, обмениваясь состояниями. Последнее не просто удобно, а это одновременно формально выверенная процедура взаимодействия автоматов, которая, если потребуется, верифицируется операцией параллельной композиции автоматов.

Сетевая автоматная модель — суть ВКПа. Не признавать ее параллелизм — это лишать человека права дышать, рыбе жить в воде, а птице летать. Ведь, не нужно уточнять, что человек дышит, рыба плавает, а птица летает, а потому нет нужды каждый раз долбить и долбить оговаривать, что ВКПа — это про параллелизм. Можно, правда, называть это «авторским взглядом», но это тот взгляд, который отражен во множестве статей автора и не только на Хабре. Нужны ли еще какие-то аргументы, чтобы отрицать параллелизм ВКПа?

На мой взгляд, если какие-то аргументы и понадобятся, то только в ситуациях, которые невозможно создать/описать в рамках алгоритмической параллельной модели среды ВКПа. И если вдруг (!) такое случится, то это будет крушением основ дискретной кибернетики, в которой автоматы составляют базу [4]. Формально, конечно,  подобное исключать нельзя. Допускаю даже,  что, может быть, это когда-либо и случится. Но это сродни тому, как пока нельзя доказать отсутствие/наличие Бога. Здесь все сходится к тому, что, как минимум, при жизни автора это не произойдет. Хотя, как знать… Может, где-то что-то уже есть и осталось только опубликовать?

3. Автоматы и SimInTech

Перейдем от общих слов к конкретным делам. И тут вспомним про SimInTech, представив свой вариант реализации автоматных процессов на примере его демонстрационного проекта «Нагреватель» [2]. В этот раз блоками приложения будут автоматные параллельные процессы, реализованные  по определенному шаблону на внутреннем ЯП среды.  Пример такого решения  приведен на рис. 1.

Рис. 1. Реализация проекта «Нагреватель» на автоматах
Рис. 1. Реализация проекта «Нагреватель» на автоматах

В нем созданы аналоги всех блоков исходного  решения в SimInTech (см. рис. 2, а подробнее в [2]). Можно было «упаковать» блоки в субмодели, как это сделано в исходной модели (а мы это еще сделаем), но пока все они будут открыты для оценки структуры и связей проекта.

Рис. 2. Исходный проект Нагреватель
Рис. 2. Исходный проект Нагреватель

Рассмотрение начнем с задержки, код которой приведен в листинге 3. Она стартует, когда ее вход (bStart) примет значение не равное нулю. Далее задержка измеряется в дискретных шагах проекта. При этом само ее значение задается в микросекундах — вход delay. На выход блока задержки выдается текущее значение числа шагов задержки – выход value и признак ее активности – выход State (0 — не активна, 1 – активна).

Листинг 3. Код блока «Задержка»

Замечание 1. Чтобы задержка отработала верно, необходимо не только установить значение входа, но до ее истечения его сбросить. В противном случае задержка будет запущена повторно.

Листинг 4. Код блока «Управление»

На листинге 4 представлен код контроллера нагревателя (на рис. 1 – блок «Управление»). Здесь сразу же, т.е. на первом переходе, запускается задержка (40 сек). Для этого нужно установить выход out40 и затем, перейдя в состояние 1 (состояние отключения нагревателя), дождавшись инициации задержки, сбросить тот же сигнал out40. Когда интервал задержки истечет, а температура воды будет меньше заданной, переходим в состояние включения нагревателя – 2, выдав при этом сигнал запуска задержки 20 сек – выход out20. Затем, аналогично состоянию 1 сбрасываем сигнал запуска задержки и ожидаем ее завершения или превышения температуры уставки.  Дождавшись или того, или другого, переходим в состояния отключения нагревателя. Далее все повторяется.

Замечание 2. Код автомата на листинге 4 демонстрирует использование «теневого состояния» — tmpState. В процессе работы новое текущее состояние автомата записывается сначала в него, чтобы на новом цикле работы модели стать текущим состоянием. 

Рис. 3. Результаты тестирования модели
Рис. 3. Результаты тестирования модели

На рис. 3 приведены результаты тестирования модели. Обращают на себя внимание графики работы задержек. Если до 460-й секунды задержки работают строго последовательно, то далее они пересекаются. На работе модели это не сказывается, но,  если подходить строго, такого быть не должно. Для устранения замеченного «непорядка» достаточно ввести сигнал сброса/останова работы задержки.

Замечание 3. Графики задержек демонстрируют параллелизм работы блоков в SimInTech.

4. Где собака порылась?

Но все же, в каком блоке скрываются проблемы «автоматов» исходного проекта? Для локализации ошибки провернем «обратный рефакторинг». В этих целях заменим блоки интегратора – «Интегратор» и ключа – «Key» (см. рис. 1) блоком «Модель нагревателя» из исходного проекта. Получим модель, показанную на рис. 4. Тестирование показало, что результаты работы не изменились. Следовательно, проблема скрывается в блоке «контроллер нагревателя» (см. рис. 2). Только в чем же конкретно эта проблема – вопрос к авторам проекта.

Рис. 4. Тестирование субмодели «Модель нагревателя»
Рис. 4. Тестирование субмодели «Модель нагревателя»

5. Создание модели управления индикацией работы нагревателя

Мы создали модель управления и модель нагревателя, но для реализации в полном объеме технического задания необходимо создать еще и управление индикатором. Возьмем за основу модель, предложенную в статье [1]. Но сначала, используя правильные и хорошие качества SimInTech, запрячем наше управление в субмодель. Такое решение показано на рис. 5.

Рис. 5. Создание субмодели «Управление нагревателем»
Рис. 5. Создание субмодели «Управление нагревателем»

Теперь можно приступать к модели управления индикатором. Она, как и в [1], будет состоять из автоматов – параллельных автоматов (!) — автоматы зеленого и красного цветов. Именно такое решение показано на рис. 6, где кроме самого проекта – рис. 6а, раскрыта структурная модель субмодели «Индикация» — рис. 6б и далее субмодели «Остывание» и «Нагрев» — рис. 6в и рис. 6г соответственно. А уже их блоки, реализованные на ЯП, приведены соответственно на листингах 5 и 6. 

И все бы хорошо, если бы не график индикации, приведенный на рис. 7. Сильно смущает однократный всплеск при переключении индикатора с красного на зеленый (после 475-й секунды).  Похоже, что в этот момент суммируются (см. оператор суммы на рис. 6б) значения, определяющие текущий цвет индикатора. По замыслу этого быть не должно.

Рис. 6. Создание субмодели «Индикация»
Рис. 6. Создание субмодели «Индикация»
Рис. 7. График включения индикатора
Рис. 7. График включения индикатора

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

Рис. 8. Автоматы модели управления нагревателем
Рис. 8. Автоматы модели управления нагревателем

Структуру модели «Управление нагревателем» с учетом новых задержек (задержки с сигналом сброса) демонстрирует рис. 9. Заметим, что буферный блок для выхода numstate введен, чтобы транслировать  на его выход только состояния 0 и 1, игнорируя остальные состояния блока «Управление» (см. на рис. 8 автомат HeatCntrl и его состояния — 77, 40 и 20).

Рис. 9. Структурная модель блока «Управление»
Рис. 9. Структурная модель блока «Управление»
Листинг 5. Коды блоков управления индикатором.
input bInStateHeat, bInStateLed, bIn5sec; output nOutColorLed, curState, out5sec; var tmpState=0; curState = tmpState;  if curState=0 and bInStateHeat = 0 and bIn5sec = 0 and bInStateLed = 0 then  begin out5sec=1; nOutColorLed = 1; tmpState = 51; end if curState=51 and bIn5sec > 0 then begin out5sec=0; tmpState = 1; end if curState=1 and bIn5sec = 0 then begin out5sec = 1; nOutColorLed = 0; tmpState = 50; end if curState=1 and bInStateHeat = 1 then  begin nOutColorLed = 0; tmpState = 0; end// переход при резком изменении режима if curState=50 and bIn5sec > 0 then begin out5sec=0; tmpState = 0; end  input bInStateHeat, bInStateLed, bIn5sec; output nOutColorLed, curState, out5sec; var tmpState=0; curState = tmpState; if curState=0 and bInStateHeat = 1 and bIn5sec = 0 and bInStateLed = 0 then begin out5sec=1; nOutColorLed = 2; tmpState = 51; end if curState=51 and bIn5sec > 0 then begin out5sec=0; tmpState = 1; end if curState=1 and bIn5sec = 0 then begin out5sec = 1; nOutColorLed = 0; tmpState = 50; end if curState=1 and bInStateHeat = 0 then  begin nOutColorLed = 0; tmpState = 0; end// переход при резком изменении режима if curState=50 and bIn5sec > 0 then begin out5sec=0; nOutColorLed = 0; tmpState = 0; end 

А теперь поговорим начистоту. Среда SimInTech – программная реализация, как представляется, гениальной идеи,  однако, требующее  существенной проверки и доработки. Это пояснит почти любой программист, хорошо знакомый с обычными универсальными языками программирования и средами их разработки — IDE. С гениальностью – сложнее. Лично меня давно «сразила» среда МВТУ, которая единственная на тот момент ввела RS-триггер в режим генерации (правда, ненадолго).  А поскольку она  – предтеча SimInTech, то восхищение первой естественным образом распространилось и на вторую. Тем более, что в SimInTech есть и другие интересные и интересующие меня черты.  

В контексте обсуждения понятия «гениальность» хочется возразить тем, кто считает Россию лучшей страной в мире. Она – не лучшая. Но  Россия в чем-то гениальная страна, выживающая в жестком  мире рыночной экономики за счет своих гениальных качеств, которые пока еще работают.  Помнится, когда-то меня очень впечатлил мультик «Самый, самый, самый, самый». В нем львенок стремится стать самым сильным, самым красивым, самым отважным, самым умным или, короче, самым, самым, самым. Хотя бы потому, что по определению он «Царь зверей». В конечном итоге он им и становится (а куда тут денешься – по праву рождения), но до него доходит, что каким бы сильным он не был – найдется сильнее, каким бы ты красивым не стал – найдется красивее, найдутся отважнее, быстрее, умнее и т.д. и т.п. Бывает и такое – умный царь! И лев — уже взрослый лев — понимает, что главное счастье — найти того, в глазах кого ты будешь самым-самым-самым-самым. И он находит – ее (правда, что уж там скрывать, она его). Ту, для которой он самый-самый. Счастливый конец.  Конец, ради которого стоит жить и творить льву и, наверное, любому другому… Так что – смотрите мультики. Лучше старые, советские мультики…  А не этот, как его, — «Король Лев».  

Россия – далеко не лучшая страна мира. Это факт – статистический. Но есть много, очень много, даже миллионы людей, для которых она самая-самая. И это главное для России, да и, надо понимать, для любой другой страны мира. Смысл жизни: не стремиться быть самым-самым и для этого лезть из кожи. Быть «халифом на час» — не тот путь, который приведет к счастливой жизни. Ну и, конечно, Россию.

Среда SimInTech – явно не лучшая среди себе подобных. Но в ней есть нечто, что на текущий момент делает ее для меня единственной и неповторимой. Познакомившись с SimInTech лишь недавно (с конца прошлого – 2022 года) и, что там скрывать,  зная ее достаточно поверхностно, это, тем не менее, позволило в ней реализовать важные для меня «автоматные идеи». Со средой МАТЛАБ такой «любви» как-то не случилось, хотя знаком с ней достаточно давно.  Почему так – объяснять, наверное, долго и нудно. Но факт остается фактом – не случилось и все тут. Хотя, как теперь понимаю, в ней можно тоже провернуть нечто подобное. Но все равно SimInTech – первая. Как первая любовь…

Автоматы в SimInTech – совсем не те автоматы, которые я могу признать и даже назвать автоматами. Безусловно, есть и, вероятно, будут те, кто со мной не согласится, и для них они — самые-самые конечные автоматы (как и диаграммы Харелла). Но только, похоже, они теорию автоматов давно не пересматривали. Или они ее просто не признают или уж, что совсем крайний случай, о ней они просто не знают…  

Но, как ни крути, в теорию автоматов я все же влюбился раньше. Но ни что не мешает ее чертами наградить и SimInTech. Как это сделать в первом приближении мы показали выше.  Может это сложнее того, чем можно было бы сделать, если подумать, но, зато, много надежнее. И уж точно лучше, чем ничего.

Литература

1.       Автоматное программирование в SimInTech и ВКПа. [Электронный ресурс], Режим  доступа: https://habr.com/ru/post/709358/ свободный. Яз. рус. (дата обращения 28.02.2023).

2.       Конечные автоматы в среде динамического моделирования SimInTech. [Электронный ресурс], Режим  доступа: https://habr.com/ru/post/307090/ свободный. Яз. рус. (дата обращения 28.02.2023).

3.       Модель параллельных вычислений. [Электронный ресурс], Режим  доступа: https://habr.com/ru/post/486622/ свободный. Яз. рус. (дата обращения 28.02.2023).

4.       Глушков В.М. Введение в кибернетику. Изд-во АН Украинской ССР. К.:  1964. — 324с.

5.       Автоматная модель управления программ. [Электронный ресурс], Режим  доступа:  https://habr.com/ru/post/484588/ свободный. Яз. рус. (дата обращения 28.02.2023).


ссылка на оригинал статьи https://habr.com/ru/post/719592/

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *