Вопрос о новичке: у Меня есть приложение форм. Это имеет отдельный поток, который выполняет вызов веб-сервисов и затем отправляет результаты вызова к основной форме.
В моем потоке, после того, как X секунд передали (использование TTimer), я звоню:
procedure TPollingThread.OnTimer(Sender: TObject);
var
SystemProbeValues : TCWProbeValues;
begin
SystemProbeValues := Remote.Run.GetSystemProbeValues;
PostMessage( ParentHandle, WM_APIEVENT ,Integer(apiMultiCellStatus), Integer(SystemProbeValues) );
end;
Удаленная функция. Выполненный. GetSystemProbeValues имеет следующий прототип:
function GetSystemProbeValues : TCWProbeValues; stdcall;
И TCWProbeValues является динамическим массивом объектов TCWProbeValue (который все убывание от TRemotable).
В моей основной форме я получаю сообщение очень хорошо и бросаю LParam назад в TCWProbeValues:
procedure TFrmCWMain.OnAPIEvent(var msg: TMessage);
begin
ProbeValues := TCWProbeValues(msg.LParam);
end;
Мой вопрос, учитывая, что динамический массив и его объекты были созданы Delphi система HTTORIO, кто ответственен за освобождение их? Delphi полагал что память допускающий повторное использование после моей функции OnTimer возвращенный? (И, в этом случае, его чистая удача, что мой основной обработчик сообщений формы может на самом деле считать память, на которую ссылается LParam сообщения?) Или скорее это моя обязанность освободить объект, который автоинстанцирует запрос HTTPRIO?
Большое спасибо, кричите, если вышеупомянутые потребности больше детали / код и я добавим к нему!
С наилучшими пожеланиями, Duncan
TRemotable
обеспечивает управление временем жизни через свойство DataContext
, поэтому среда выполнения SOAP сама освободит объект. Пока существует объект data-context, будет существовать и все, что он выделил. Если вы хотите заявить о своем праве собственности и ответственности за объект, просто очистите его свойство DataContext
. (Вероятно, именно это вы захотите сделать в данном случае, поскольку ваше сообщение об API-событии может быть обработано после завершения SOAP-события.)
Проблема в вашем коде заключается в том, что вы передаете динамический массив через отправленное сообщение. Когда ваша процедура OnTimer
возвращается к своему вызывающему пользователю, динамический массив, на который ссылается SystemProbeValues
, будет иметь уменьшенное количество ссылок. Если другой поток еще не обработал сообщение (а он, скорее всего, не обработал), то динамический массив может быть уничтожен к тому времени, когда он доберется до обработки этого сообщения.
Простой способ обойти это - очистить ссылку в обработчике события таймера, не уменьшая счетчик ссылок, а затем сделать обратное в обработчике сообщения. После отправки сообщения очистите переменную:
LParam(SystemProbeValues) := 0;
В обработчике сообщения очистите старое значение глобальной переменной ProbeValues
и присвойте новое значение следующим образом:
ProbeValues := nil;
LParam(ProbeValues) := Msg.LParam;
Другая проблема, скрывающаяся в вашем коде, может заключаться в использовании TTimer
в потоке, не относящемся к VCL. Этот класс создает хэндл окна для совместного использования всеми экземплярами класса. Если ваш поток таймера не является единственным потоком в программе, использующим TTimer
, у вас, вероятно, возникнут проблемы, либо функции будут выполняться не в том потоке, либо не будут выполняться вообще. Вместо TTimer
вы можете использовать SetTimer
для создания таймера ОС вручную, или вы можете создать waitable timer, который может быть более подходящим для использования в потоке, который не должен реагировать на действия пользователя.