Обновить запросы в темах
Я использую 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
к конструктору этого потока. Я могу предположить, я полагаю, что этот запрос имеет сходство с основным потоком - это означает, что он (возможно) является визуальным компонентом в форме, имеет привязки данных к визуальным компонентам или иным образом взаимодействует с пользователем или пользователем интерфейс.
Ответ, если так, заключается в том, что вы просто не можете сделать это - поток не может изменить объект со сродством к другому потоку. Ваш интерфейс может быть в процессе извлечения записей из запроса, когда, например, фоновый поток одновременно уничтожает их при подготовке к обновлению содержимого запроса. Естественно, это вызовет все виды проблем.
Простым решением является использование обычного таймера и синхронное обновление в основном потоке. Если это занимает слишком много времени, вам нужно рассмотреть другую стратегию. У нас нет достаточной информации, чтобы предлагать гораздо больше. Если доступ к сети и ввод-вывод являются узким местом, то вы можете рассмотреть возможность асинхронного обновления отдельного объекта запроса, принадлежащего потоку, а затем синхронно назначить его компонентам представления.