Можно ли как-то определить, что Pascal Script простаивает?

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Можно ли как-то определить, что Pascal Script простаивает?

Сообщение Aleks69 » 12.06.2020 00:58:52

Добрый день.

Есть родительское приложение, которое дергает процедуры внутри PS ( через GetProcMethod(Function_Name) ), передавая им строковые данные, которые приходят от нескольких внешних источников (UDP, TCP, RS232, которых, разумеется, самих может быть по несколько штук). На каждый источник - своя процедура для обработки. То есть имеется головное приложение, которое в идеале не перекомпилируется, и подсистема Pascal Script в нем, на котором пользователь пишет свою программу по обработке данных, поступающих от разных источников. Если еще точнее, у меня есть готовое приложение - визуализатор, которому желательно придать больше гибкости без перекомпиляции.

К основному приложению я кое-что уже прикрутил, и это работает, нужные процедуры, описанные внутри PS также вызываются и получают извне данные. Вот что можно создать и использовать из PS (экземпляры этого, создаются, естественно, в основном приложении):

1. Создаются UDP "серверы" и "клиенты" на базе Synapse (m_pSocket := TUDPBlockSocket.Create;) Каждый новый экземпляр в отдельном потоке.

2. Создаются TCP серверы и клиенты на базе Indy 10 + его же Antifreeze. Тут, я понимаю, отдельные потоки создаются автоматически.

3. Просто создаются экземпляры Cport.TComPort. Вот тут честно говоря не знаю с потоковой моделью. С несколькими экземплярами (разными COM-портами) работу пока толком не проверял. Но с одним Com-портом из PS обмен данными устойчивый.

Главный вопрос вот в чем: судя по всему, PS устроен так, что вызов какой-то другой процедуры, пока работает первая, не допустим. Время выполнения процедур на PS у меня, в общем-то не большое, но накладки будут обязательно. Самое простое, видимо, сделать внешний флаг, который быдет устанавливать и сбрасывать каждая процедура, работающая внутри PS а очередь исполнения внутренних процедур опять же всести снаружи, вне PS. Но не хотелось бы, чтобы пользователи PS задумывались о флагах, а просто писали бы, "как обычно". Не думая о порядке выполнения как таковом.

Флаг, что процедура на PS завершила свою работу, и основное приложение может вызывать опять эту же или другую процедуру из PS мне пока кажется единственным, но каким-то кривым решением. Это значит навязывать пользователю некую парадигму оформлени процедур, отличную от чисто Паскалевской. Вот думаю, и ничего не придумывается пока получше.
Aleks69
новенький
 
Сообщения: 35
Зарегистрирован: 29.03.2009 14:25:01

Re: Можно ли как-то определить, что Pascal Script простаивае

Сообщение Alex2013 » 13.06.2020 12:04:14

По моему ничего не мешает поднять флаг перед вызовом PSScript1.Execute и опустить после, а при повторном вызове ожидать пока он не опустится и только потом запускать скрип . (кстати не плохо-бы таймаут для "повисшего" скрипта добавить )
А вообще по моему достаточно создавать и уничтожать екземпляр PSScript отдельно для каждого потока ( Правда придется его еще и "компилировать" каждый раз, но это не так уж и накладно, так как на фоне времени работы самого скрипта обычно почти незаметно ).
Alex2013
долгожитель
 
Сообщения: 2923
Зарегистрирован: 03.04.2013 11:59:44

Re: Можно ли как-то определить, что Pascal Script простаивае

Сообщение Aleks69 » 13.06.2020 17:01:27

Добрый день. Спасибо за ответ. С PS работаю впервые.

Вчера на ночь сделал так. В основном приложении очередь, точнее две копии, на основе пользовательского класса, ("родная" очередь в D2006 оказалась неудобной, т.к. ее реализация старая, работает только с указателями, много лишних телодвижений ), которые заполняются синхронно при поступлении данных по каналам TCP и RS-232. В первой очереди храниться имя процедуры внутри PSScript, во второй - собственно сами данные, предназначенные для обработки этой процедурой. Занесение элементов в очереди сделано так:

Код: Выделить всё

procedure TForm3.Add_to_Queue(Function_Name_To_Get_Input_Data: String; Data_String: String); // Помещение в очередь
Begin
     Try
      CriticalSection.Enter;
      Function_Name_Queue.Enqueue(Function_Name_To_Get_Input_Data);
      Data_String_Queue.Enqueue(Data_String);
     Finally
      CriticalSection.Leave;
     End;

End;



Разумеется, Add_to_Queue вызывается из разныйх мест - сейчас по приходу данных по каналу TCP и по RS-232. Вопрос - так до сих пор и не нашел однозначного ответа, если код в критической секции занят, другой запрос просто отбрасывается, и повторные попытки нужно оформлять самостоятельно, или из другого потока запрос на выполнение процедуры будет выпонен автоматически, с определенным числом попыток например?

Выборка из очереди производится внутри самодельного таймера с интервалом 10 миллисекунд, на основе MMSystem.

Внутри таймера:

Код: Выделить всё

procedure TimerProc(uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWORD) stdcall; // Обработка очереди

begin

If PS_IS_Ready='No' Then Exit;  // Флаг доступный процедурам PS. Означает, что сейчас выполняется та или иная процеура внутри PS
If Function_Name_Queue.isEmpty Then Exit;

PS_IS_Ready:='No';  // Устанавливаем флаг
Form3.Call_PS_Function(Function_Name_Queue.Dequeue, Data_String_Queue.Dequeue, '', ''); // Вызываем процедуру обработки внутри скрипта

end;



сразу выставляется в доступной и для PSScript внешней переменной - PS_IS_Ready:='No'. Внутри обрабатывающих процедур, уже в PSScript, при окончании работы процедуры ставится PS_IS_Ready:='Yes'

Код отработал несколько часов, данные от прибора поступали со скоростью 115200 по RS-232 десять раз в секунду. Посылки около 64 байт. Число посылок от прибора и на него - по 233 тысячи. При этом по TCP тоже были редкие посылки, до 300 примерно за все время, которые также были корректно обработаны соотв. процедурой внутри скрипта.

Все вроде отработало, но есть ощущение, что что-то сделано не правильно, нужно как-то по другомую. Буду рад любым замечаниям.

Создавать экземпляр PSScript отдельного потока здесь пожалуй не получится - кто знает, как пользователь будет писать свою программу и какие общие переменные захочет использовать внутри скрипта. Прокидывать в PSScript или как-то создавать динамически во внешнем приложении заранее не извесное число переменных неизвестно какого типа - велосипед будет тот еще. Хотелось бы, что бы пользователь скрипта писал с минимальными понятиями о том, как это все снаружи устроено.

Да, заметил еще такую вещь. Внутри скрипта есть еще отдельная процедура, которая никак пока не оформлена флагами. Она (сейчас по крайней мере) может быть вызвана не из очереди, а сама по себе. Эта процедура оправляет данные по TCP, дергая в свою очередь нужную процедуру в основном приложении. При этом, как будто ошибок не возникает. У меня вообще такое ощущение, что в данной ситцации PSScript "сам" приостанавливает выполнение текущей процедуры, например по обработке данных от RS-232, а потом возвращается к ней автоматически. Что-то вроде стека. Глюк это или приятная фича - пока не понятно. Если нам нужно как можно быстрее отправить команду на включение света, например, и посылка по TCP уйдет на умное реле, на долю секунды приостановив работу других процедур, то это не сташно. Но если при этом, при частом использовании, вылезут побочные эффекты и потребуется ввседение очереди уже и внутри PSScript, то это будет грустно. Время реакции может колебаться в непредсказуемых пределах!
Aleks69
новенький
 
Сообщения: 35
Зарегистрирован: 29.03.2009 14:25:01


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Google [Bot] и гости: 39

Рейтинг@Mail.ru