Долгие отчеты, форма «ожидания» в отдельном потоке.
Добавлено: 14 окт 2009, 16:34
Добрый день.
В проекте требуется выполнить формирование отчетов (запросы к БД длятся от 1 до 60 сек) с отображением формы ожидания и возможностью отмены в любой момент. При отмене долгого запроса (поскольку это не происходит мгновенно) форма ожидания должна отображаться с сообщением «отмена операции». SQL-сервер Firebird2.5Beta2, среда разработки Delphi 7.
Изучив статью http://mbo88.narod.ru/ToC.html плюс ветки, посвященные потокам, здесь на форуме, пошел таким путем:
1.Объявляю два класса
2.При вызове отчета создаю форму ожидания (в главном потоке), отображаю ее и стартую поток для отображения формы ожидания (назову его для краткости потоком ожидания)
3.Поток ожидания запускает поток расчетов. Здесь же, при отмене расчетов для снятия длительного запроса создается датамодуль, устанавливающий собственное соединение с базой, с query:
I_CUR_CONNECT получаю в Execute блоке потока расчета, который «передаю» в главный поток по Synchronize. Вообще все взаимодействие дочерних и основного потока (с VCL) делаю через Synchronize.
Код метода Execute потока ожидания:
4.В потоке расчета устанавливаю собственное соединение с БД, открываю датасет с запросом для формирования отчета. При фетче записей проверяю Terminated потока. При любом условии завершения потока расчета выполняется процедура tetSetSplashTerminate:
Все вышесказанное вроде бы логично, но не работает так, как нужно. Плюс часто выпадают access violation в самых неожиданных местах. Поскольку с потоками работаю впервые (так уж сложилось), прошу помощи.
1.В связи с тем, что часто и где попало выпадают access violation, явно нарушен сам принцип работы с потоками. Ткните пожалуйста в самые проблемные места вышеописанного алгоритма.
2.При выполнении кода, отменяющего долгий запрос, сразу после ExecQuery (поток ожидания, операция отмены), почему-то с экрана пропадает форма ожидания. Закоментарил данный кусок кода, отменяющего запрос, запустил проект, отменил формирование расчета, после чего сразу же в Ибэксперте удалил строку в MON$ATTACHMENTS – эффект тот же, пропала форма ожидания. Чем вызвано такое поведение? Соответственно, если не удаляю, то форма отображается до завершения долгого запроса.
3.Проект запущен в Delphi. Выполняю вновь операцию отмены отчета, сразу после ExecQuery вылетает ошибка EOSError ‘System error. Code: 5. Отказано в доступе’. Это нормально? Проект после этого работает.
4.Наверняка кто-то уже решал подобную задачу. По возможности, поделитесь пожалуйста своими идеями, хотя бы в общих чертах описав подход и принцип реализации такого функционала.
5.Есть еще одна проблема – обновление по таймеру текущих данных, в данном конкретном проекте – значений электропотребления для выбранной расчетной группы. Проблема в том, что при выборе детализации «год по месяцам» запрос на обновление выполняется по времени до минуты. Возможно ли вынести это обновление в отдельный поток, предусмотрев досрочную отмену операции, и каким образом (принцип в общих чертах)?
В проекте требуется выполнить формирование отчетов (запросы к БД длятся от 1 до 60 сек) с отображением формы ожидания и возможностью отмены в любой момент. При отмене долгого запроса (поскольку это не происходит мгновенно) форма ожидания должна отображаться с сообщением «отмена операции». SQL-сервер Firebird2.5Beta2, среда разработки Delphi 7.
Изучив статью http://mbo88.narod.ru/ToC.html плюс ветки, посвященные потокам, здесь на форуме, пошел таким путем:
1.Объявляю два класса
Код: Выделить всё
TSplashThread = class(TThread) //поток для отображения формы ожидания
private
tstbCancel: boolean; //признак «отмены»
procedure tstCheckStatusTerminate; //проверка статуса «отмена»
protected
procedure Execute; override;
end;
TExecThread = class(TThread) //поток для расчета и обновления формы ожидания
private
tetiProgress: integer; // прогресс бар
procedure tetSetProgress; // установка прогресс бара на форме ожидания
procedure tetSetSplashTerminate; //завершение расчета
protected
procedure Execute; override;
end;
Код: Выделить всё
if not assigned(formSplash) then
formSplash := TformSplash.Create(Application);
formSplash.Show;
SplashThread:=TSplashThread.Create(true);
SplashThread.FreeOnTerminate:=true;
SplashThread.tstbCancel := False;
SplashThread.Priority:=tpLower;
SplashThread.Resume;
Код: Выделить всё
delete from MON$ATTACHMENTS where MON$ATTACHMENT_ID=:I_CUR_CONNECT
Код метода Execute потока ожидания:
Код: Выделить всё
procedure TSplashThread.Execute;
var ExecThread: TExecThread;
begin
ExecThread:=TExecThread.Create(True);
ExecThread.FreeOnTerminate:=True;
ExecThread.Priority:=tpLower;
ExecThread.tetiProgress := 0;
ExecThread.Resume;
while (not tstbCancel) and (not Terminated) do //бесконечный цикл
begin
Synchronize(tstCheckStatusTerminate);
Application.ProcessMessages;
sleep(1);
end;
//отмена долгого запроса
dmDataDelConnects := TdmDataDelConnects.Create(Application);
dmDataDelConnects.fibDB.Connected := True;
dmDataDelConnects.fibqDelCC.Transaction.StartTransaction;
dmDataDelConnects.fibqDelCC.ParamByName('I_CUR_CONNECT').AsInteger := tstiCurConnect;
dmDataDelConnects.fibqDelCC.ExecQuery;
dmDataDelConnects.fibDB.Connected := False;
FreeAndNil(dmDataDelConnects);
ExecThread.Terminate; //останов потока расчета
end;
Код: Выделить всё
procedure TExecThread.tetSetSplashTerminate;
begin
if assigned(dmDataReps) then
begin
dmDataReps.fibDB.Connected := False;
FreeAndNil(dmDataReps);
end;
if Assigned(formSplash) then FreeAndNil(formSplash); //уничтожаю форму ожидания
end;
1.В связи с тем, что часто и где попало выпадают access violation, явно нарушен сам принцип работы с потоками. Ткните пожалуйста в самые проблемные места вышеописанного алгоритма.
2.При выполнении кода, отменяющего долгий запрос, сразу после ExecQuery (поток ожидания, операция отмены), почему-то с экрана пропадает форма ожидания. Закоментарил данный кусок кода, отменяющего запрос, запустил проект, отменил формирование расчета, после чего сразу же в Ибэксперте удалил строку в MON$ATTACHMENTS – эффект тот же, пропала форма ожидания. Чем вызвано такое поведение? Соответственно, если не удаляю, то форма отображается до завершения долгого запроса.
3.Проект запущен в Delphi. Выполняю вновь операцию отмены отчета, сразу после ExecQuery вылетает ошибка EOSError ‘System error. Code: 5. Отказано в доступе’. Это нормально? Проект после этого работает.
4.Наверняка кто-то уже решал подобную задачу. По возможности, поделитесь пожалуйста своими идеями, хотя бы в общих чертах описав подход и принцип реализации такого функционала.
5.Есть еще одна проблема – обновление по таймеру текущих данных, в данном конкретном проекте – значений электропотребления для выбранной расчетной группы. Проблема в том, что при выборе детализации «год по месяцам» запрос на обновление выполняется по времени до минуты. Возможно ли вынести это обновление в отдельный поток, предусмотрев досрочную отмену операции, и каким образом (принцип в общих чертах)?