Обновить запросы в темах

Я использую Delphi XE6, UniDAC и MySQL.

У меня есть несколько компонентов TUniQuery в моей DM, и я хочу многократно обновлять тему, поэтому я помещаю несколько таймеров в свою основную форму, и в каждом таймере я создаю поток и передаю ему запрос на обновление данных:

например:

 TUpdateThread = class(TThread)
 private
  FQuery : TUniQuery;
  FResultHandle : THandle;
 public
  constructor Create(var Query : TUniQuery; ResultHandle : THandle);
 protected
  procedure Execute; override;
 end;

constructor TUpdateThread.Create(var Query: TUniQuery; ResultHandle : THandle);
begin
 inherited Create;
 Suspend;
 FQuery := Query;
 FResultHandle := ResultHandle;
 FreeOnTerminate := True;
 Resume;
end;

procedure TUpdateThread.Execute;
var
 Msg : String;
 B : Boolean;
begin
 try
  B := True;
  try
   FQuery.Refresh;
  except
   on E:Exception do
    begin
     B := False;
     Msg := 'Error : ' + #13 + E.Message;
     SendMessage(FResultHandle, MSG_UPDATERESULT, 2, Integer(Msg));
    end;
  end;
 finally
  if B = True then
   SendMessage(FResultHandle, MSG_UPDATERESULT, 1, 1);

  Terminate;
 end;
end;

Иногда это делается успешно, но много раз я получал некоторые ошибки, такие как AV или "Net Pack Header ... ", или иногда у меня возникают проблемы в моих сетках ( Ehlib DBGrid), такие как ошибка при рисовании строк или... (особенно когда я использую DisableControls и EnableControls) Все запросы имеют одно и то же соединение, я думаю, что каждый поток должен иметь свое собственное соединение, поскольку интервалы между таймерами одинаковы, я предлагаю иногда обновление запросов прерывает друг друга

Фактически, моя база данных находится на VPS-сервере, и есть несколько клиентских приложений, я хочу иметь Live-таблицы в клиентах и ​​многократно обновлять тему

Каков наилучший способ достичь этого? как я должен обновить свои таблицы без зависаний приложения! Есть некоторые компоненты, как TThreadTimer (или...), тема полезна для этой ситуации?!

Спасибо...

1 ответ

Первый выпуск здесь:

constructor TUpdateThread.Create(var Query: TUniQuery; ResultHandle : THandle);
begin
 inherited Create;  // Create with no arguments 
 Suspend;           // means CreateSuspended = false
 FQuery := Query;
 FResultHandle := ResultHandle;
 FreeOnTerminate := True;
 Resume;
end;

Здесь вы создаете поток с конструктором по умолчанию (CreateSuspended = false) где поток начинает работать немедленно. Ты звонишь suspend (который устарел и не должен использоваться) немедленно, но это все еще условие гонки, так как ваш поток может начинать или не начинать попытки Refresh Ваш запрос, прежде чем вы его назначили. Чтобы создать поток в приостановленном состоянии, используйте конструктор перегрузки

inherited Create(true);

Resume также не рекомендуется. Вместо этого вы должны использовать Start;,

Далее вы проходите в TUniQuery к конструктору этого потока. Я могу предположить, я полагаю, что этот запрос имеет сходство с основным потоком - это означает, что он (возможно) является визуальным компонентом в форме, имеет привязки данных к визуальным компонентам или иным образом взаимодействует с пользователем или пользователем интерфейс.

Ответ, если так, заключается в том, что вы просто не можете сделать это - поток не может изменить объект со сродством к другому потоку. Ваш интерфейс может быть в процессе извлечения записей из запроса, когда, например, фоновый поток одновременно уничтожает их при подготовке к обновлению содержимого запроса. Естественно, это вызовет все виды проблем.

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

Другие вопросы по тегам