Нужна помощь профессионального программиста
Привет!
Есть MDI приложение, которое получает данные по DDE
Дочерних окон много (сейчас 99), но может быть и больше (около 140)
Из главного окна данные передаются в дочернее окно так:
В дочернем окне данные принимаются
OutData в главном окне и inData в дочернем окне объявлены как структура (Transfer data)
Для развязки окон используется
Все нормально работает, но достаточно медленно
Идет непрерывный поток данных по DDE, а дочерних окон много
и пока в дочернем окне не отработает процедура
Процесс раздачи данных по дочерним окнам приостанавливается
Если в дочернем окне убрать процедуру
А по PoatMessage вызвать её, то во входных данных уже появляются данные, предназначенные другому окну
Сам вопрос:
Как сделать, чтобы данные просто передались в дочернее окно, а уж потом, по PostMessage, они парсились?
Можно для каждого дочернего окна создавать отдельный поток и UpdExpertData(); запускать в отдельном потоке. PostMessage в отличии от SendMessage вроде асинхронная функция и во время ее работы основной поток не останавливается. Надо еще придумать какие то флаги сигнализирующие о том, что процесс в процессе :) обработки данных и пока он его не отработает не передавать новые данные этому окну. Если каждое дочернее окно будет работать в отдельном потоке, то тогда процесс передачи данных не будет останавливаться и ждать пока окно отработает данные, а сразу же будет передавать данные следующему окну. Слабое место всех MDI приложений, как раз в этом что все дочерние окна работают в одном потоке главного окна. Если для каждого дочернего окна предусмотреть отдельный поток то думаю проблема будет решена.
...
Вот накопал статейку на эту тему. https://www.ispras.ru/proceedings/docs/2017/29/1/isp_29_2017_1_231.pdf
Вот еще - https://habr.com/ru/post/144681/
....
Еще вопрос в процессе работы используете функцию Application.ProcessMessages?
- 2012.05.28
- habr.com
Можно для каждого дочернего окна создавать отдельный поток и UpdExpertData(); запускать в отдельном потоке. PostMessage в отличии от SendMessage вроде асинхронная функция и во время ее работы основной поток не останавливается. Надо еще придумать какие то флаги сигнализирующие о том, что процесс в процессе :) обработки данных и пока он его не отработает не передавать новые данные этому окну. Если каждое дочернее окно будет работать в отдельном потоке, то тогда процесс передачи данных не будет останавливаться и ждать пока окно отработает данные, а сразу же будет передавать данные следующему окну. Слабое место всех MDI приложений, как раз в этом что все дочерние окна работают в одном потоке главного окна. Если для каждого дочернего окна предусмотреть отдельный поток то думаю проблема будет решена.
...
Вот накопал статейку на эту тему. https://www.ispras.ru/proceedings/docs/2017/29/1/isp_29_2017_1_231.pdf
Вот еще - https://habr.com/ru/post/144681/
....
Еще вопрос в процессе работы используете функцию Application.ProcessMessages?
Спасибо, конечно, но Вы вероятно не поняли.
Дочернее окно лишь окно, в котором отображается информация, в всю работу выполняет класс
type TExpert = class FFutName: string; FSpotName: string; FFutAccaunt: string; FSpotAccaunt: string; FFXAccaunt: string; FClient: string; FTransBusy: boolean; FOrder: EntityNumber; FTransID: DWord; FExpData: TExpertData; FEHandle: THandle; FMaxValue: Double; FMinValue: Double; FTransAction: TTRansID; FStopTrading: boolean; FMemo: TMemo; FCEntLabel: TLabel; FСExitLabel: TLabel; FFutLabel: TLabel; FSpotLabel: TLabel; FMaxLabel: TLabel; FMinLabel: TLabel; FCBLabel: TLabel; FIntLabel: TLabel; FExtLabel: TLabel; FDivLabel: TLabel; FAvlLabel: TLabel; FMCntLabel: TLabel; FDeltaLabel: TLabel; FCurDivLabel: TLabel; FSettings: TExpertSettings; FFutVol: double; FSpotVol: double; FInData: TTransData; FOrderPrice: Double; FTrRes: Long; FExCode: Long; FTCode: Long; FRepMess: LPSTR; FVolume: Quantity; FaSell: Long; FMustSpotVol: double; FDllConn: boolean; FQConn: boolean; FWrongData: TWrongData; FEntEdit: TEdit; FExitEdit: TEdit; private procedure OnTick(); procedure UpdExpertData(); function CheckTime(var is_rem_order: boolean): boolean; function CalcProc(var inVal, outVal, CBuy, aDelta, Cdivs, iSell, oBuy: double): boolean; function PositionState(): POS_STATE; function GetFutInVolume(const aVol: double): double; function CheckMoney(const vol: double): double; procedure SendOrder(const dir: integer; const price: double; const qnty: double); function GetTransID(): dword; function CheckPosEqual(): double; function GetFutOutVolume(const aVol: double): double; procedure SellBuySpot(const aVol: double; const BuySell: integer); function CheckFutPrice(const aPrice: double): boolean; public constructor Create(); destructor Destroy; override; procedure OnTrade(); procedure OnError(); // procedure OnOrder(); //--- Property property FutName: string read FFutName; property SpotName: string read FSpotName; property FutAccaunt: string read FFutAccaunt; property SpotAccaunt: string read FSpotAccaunt; property FXAccaunt: string read FFXAccaunt; property Client: string read FClient; property TransBusy: boolean read FTransBusy; property Order: EntityNumber read FOrder; property TransID: DWord read FTransID; property ExpData: TExpertData read FExpData; property EHandle: THandle read FEHandle; property MaxValue: Double read FMaxValue; property MinValue: Double read FMinValue; property TransAction: TTRansID read FTransAction; property StopTrading: boolean read FStopTrading; property Memo: TMemo read FMemo; property CEntLabel: TLabel read FCEntLabel; property СExitLabel: TLabel read FСExitLabel; property FutLabel: TLabel read FFutLabel; property SpotLabel: TLabel read FSpotLabel; property MaxLabel: TLabel read FMaxLabel; property MinLabel: TLabel read FMinLabel; property CBLabel: TLabel read FCBLabel; property IntLabel: TLabel read FIntLabel; property ExtLabel: TLabel read FExtLabel; property DivLabel: TLabel read FDivLabel; property AvlLabel: TLabel read FAvlLabel; property MCntLabel: TLabel read FMCntLabel; property DeltaLabel: TLabel read FDeltaLabel; property CurDivLabel: TLabel read FCurDivLabel; property Settings: TExpertSettings read FSettings; property FutVol: double read FFutVol; property SpotVol: double read FSpotVol; property InData: TTransData read FInData; property OrderPrice: Double read FOrderPrice; property TrRes: Long read FTrRes; property ExCode: Long read FExCode; property TCode: Long read FTCode; property RepMess: LPSTR read FRepMess; property Volume: Quantity read FVolume; property aSell: Long read FaSell; property MustSpotVol: double read FMustSpotVol; property DllConn: boolean read FDllConn; property QConn: boolean read FQConn; property WrongData: TWrongData read FWrongData; property EntEdit: TEdit read FEntEdit; property ExittEdit: TEdit read FExitEdit; end;
И в этом экземпляре Класса есть переменная (FInData: TTransData) - в которую принимаются данные, а дочерняя форма служит лишь для идентификации экземпляра класса и содержит несколько функций, через которые можно обращаться
к данному экземпляру класса. Что поток запускать (кстати тоже класс), что экземпляр Класса - одно и тоже.
Спасибо, конечно, но Вы вероятно не поняли.
Дочернее окно лишь окно, в котором отображается информация, в всю работу выполняет класс
И в этом экземпляре Класса есть переменная (FInData: TTransData) - в которую принимаются данные, а дочерняя форма служит лишь для идентификации экземпляра класса и содержит несколько функций, через которые можно обращаться
к данному экземпляру класса. Что поток запускать (кстати тоже класс), что экземпляр Класса - одно и тоже.
Не одно и тоже. Почитайте что такое многопоточные приложения. Вы говорите, что во время работы функции UpdExpertData() передача данных следующему окну не происходит. Что бы этого избежать надо что бы эта функция запускалась в отдельном потоке. И эти разные потоки будут работать одновременно (параллельно). Если вы запускаете просто экземпляр класса а затем еще какой то экземпляр класса в рамках одного потока. То второй класс как бы стоит в очереди пока не отработает 1-й запущенный класс. А если каждый класс запустить как два отдельных потока то они будут выполнятся одновременно и при этом еще будет работать главный поток.
Все прекрасно работает, но функция OnData()
procedure TMDIChild.OnData; var done: boolean; begin FExpert.FinData:= TTransData(Data^); //resive data Mutex.Lock; try done:= Expert.TransBusy; //Ckeck transaction in progress finally Mutex.Unlock; end; if(done = false) then FExpert.UpdExpertData(); //Uрdate expert data end;
Исполняется достаточно долго, потому что приходится вызывать
FExpert.UpdExpertData()
иначе, (если не вызывать UpdExpertData(), когда приходит PostMessage в буфере уже данные для другого экземпляра класса.
Нет, это робот, а не кинопроектор, отображение информации на дочерней форме это не главное, главное это вычисления и команды, которые выполняет экземпляр Класса TExpert
Application.ProcessMessages не только для отображения. PostMessage это постановка сообщения в конец очереди, SendMessage это отправка сообщения без очереди. ProcessMessages как бы заставляет принудительно выполнить сообщение находящееся в очереди.
Все прекрасно работает, но функция OnData()
Исполняется достаточно долго, потому что приходится вызывать
иначе, (если не вызывать UpdExpertData(), когда приходит PostMessage в буфере уже данные для другого экземпляра класса.
Получается, что у вас поток данных не синхронизирован. PostMessage ставит в очередь оно асинхронное (как писал выше) если долго работает UpdExpertData() нужно не посылать PostMessage пока не отработает UpdExpertData(). SendMessage после отправки сообщения дожидается отработки и ждет результата , Post же просто кладет сообщение в очередь. Выше немного не правильно написал. SendMessage тоже в очередь помещает сообщение.
Получается, что у вас поток данных не синхронизирован. PostMessage ставит в очередь оно асинхронное (как писал выше) если долго работает UpdExpertData() нужно не посылать PostMessage пока не отработает UpdExpertData().
Так сейчас и реализовано,
Child.OnData(@OutData); //Send data PostMessage(Child.Expert.EHandle, WM_ON_TICK, Child.Expert.EHandle, 0); //Init OnTick
но при этом притормаживается отдача данных в другой эксперт
А нужно просто передать данные, передал и вызвал PostMessage()
А PostMessage() вызовет OnTick() к классе, который и обработает данные.
У меня не получается "обрубить" передаваемый буфер.Так сейчас и реализовано,
но при этом притормаживается отдача данных в другой эксперт
А нужно просто передать данные, передал и вызвал PostMessage()
Попробуйте смоделировать ситуацию. Вызвали Child.OnData(@OutData); он отработал дальше PostMessage поставила в очередь сообщение №1. Оно в очереди и пока еще не отработано или в процессе работы. Потом опять Child.OnData(@OutData) и следом PostMessage №2 ставится в очередь. При этом сейчас обрабатывается сообщение №1. И так далее. Нужна синхронизация.
Попробуйте смоделировать ситуацию. Вызвали Child.OnData(@OutData); он отработал дальше PostMessage поставила в очередь сообщение №1. Оно в очереди и пока еще не отработано ил в процессе работы. Потом опять Child.OnData(@OutData) и следом PostMessage №2 ставится в очередь. При этом сейчас обрабатывается сообщение №1. И так далее. Нужна синхронизация.
Вы не понимаете, что PostMessage() не ноиер 1 и номер 2 и т.д
Postmessage() посылается в конкретное окно, мало того в один из параметров заносится хендл окна
PostMessage(Child.Expert.EHandle, WM_ON_TICK, Child.Expert.EHandle, 0); //Init OnTick
Child.Expert.EHandle
Это идентификатор окна в которое посылается сообщение.
BOOL PostMessageA( [in, optional] HWND hWnd, [in] UINT Msg, [in] WPARAM wParam, [in] LPARAM lParam );
[in, optional] hWnd Type: HWND A handle to the window whose window procedure is to receive the message. The following values have special meanings.
Привет!
Есть MDI приложение, которое получает данные по DDE
Дочерних окон много (сейчас 99), но может быть и больше (около 140)
Из главного окна данные передаются в дочернее окно так:
В дочернем окне данные принимаются
OutData в главном окне и inData в дочернем окне объявлены как структура (Transfer data)
Для развязки окон используется
Все нормально работает, но достаточно медленно
Идет непрерывный поток данных по DDE, а дочерних окон много
и пока в дочернем окне не отработает процедура
Процесс раздачи данных по дочерним окнам приостанавливается
Если в дочернем окне убрать процедуру
А по PoatMessage вызвать её, то во входных данных уже появляются данные, предназначенные другому окну
Сам вопрос:
Как сделать, чтобы данные просто передались в дочернее окно, а уж потом, по PostMessage, они парсились?