2015-09-22 5 views
0

I`m с помощью Delphi XE6 и UniDAC и MySQLОбновить Запросы в Threads

У меня есть некоторые компоненты 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; 

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

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

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

благодаря ...

+3

Не используйте приостановку/возобновление. Эти методы устарели.Вместо этого создайте приостановленный поток и «запустите» его при инициализации – Johan

+2

Не отправляйте «SendMessage» из своего потока. Подумайте, что произойдет, если приемник начнет обрабатывать его. Используйте «PostMessage» или «SendMessageTimeout», чтобы убедиться, что ваш поток не будет умирать в этой строке. Вот почему 'Синхронизация' не реализована, как только этот вызов одной функции. – TLama

+0

@TLama: но Postmessage отправил сообщение в очередь messae и получил задержку! , много раз, когда я создаю поток, я показываю окно ожидания, и нет работы до тех пор, пока сообщение не поступит –

ответ

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 конструктору этой нити. Можно предположить, я полагаю, что этот запрос имеет сродство к основному потоку - это значит, что он (возможно) визуальный компонент в форме, имеет привязки к визуальным компонентам или иным образом взаимодействует с пользователем или пользователем интерфейс.

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

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

+0

Другими словами, создайте и инициализируйте UniQuery внутри потока, а при завершении потока передайте UniQuery в форму. В этом случае вы просто передадите SQLtext в Thread как paramater. – Johan

+1

Возможно, стоит упомянуть, что ClientDataSets предоставляет простой способ передачи данных между рабочим потоком и VCL одним, назначив свойство данных CDS рабочего потока. – MartynA

+0

Я пробовал использовать Start, но когда я создаю поток, отображается сообщение об ошибке: «невозможно запустить« Начать в запущенном или приостановленном потоке », что пойдет не так?! –