-
У меня есть проект, написанная на Delphi. Проект включает одну службу, которая, кроме основного потока, имеет еще и дополнительный. Оба потока работают все время функционирования службы. Можно ли как-нибудь получить возможность централизованно перехвата всех исключений, которые возникнут в любом месте службы? В идеале в любом месте запущенного exe (т.к. он может содержать несколько служб и имеет еще общий для всех служб поток, в котором вызывается Run()).
Дело в том, что все исключения дополнительного потока Delphi «съедает», если их не обработал разработчик. Кроме того в основном потоке службы есть таймер. Я охватил OnStart и OnTimer блоками try/except. Но что если исключение вылезет внутри «фреймворка»? Т.е., например, внутри «процедуры», которая запускает OnTimer? Или внутри механизма, пускающего execute у потока? В общем, я хочу иметь возможность перехватывать все исключения. Желательно централизованно.
Заранее спасибо.
PS: В Net вот есть такой механизм. Пусть и не буз своих заморочек (хотя скорее всего я просто его недопонял еще). А в Delphi потоки молча ловят исключения и у сервиса нет onexcept (хотя я могу запросто использовать ApplicationException, который просто не будет функционировать). «Жалоб нет, но как-то неаккуратно выглядит» ©
-
Охвати в try..except тела каждого из обработчиков ServiceStart, ServiceStop, ServiceExecute каждого сервиса в составе своего ServiceApplication - этим ты будешь контролировать исключения в тредах, автоматически создаваемых твоим ServiceApplication.
Для тредов, явно создаваемых тобой самим, либо охватывай в try..except тела Execute (при использовании TThread) либо обрабатывай Application.OnException.
-
> [1] Сергей М. © (30.11.11 10:46)
Тоесть охватывание try/except всех обработчиков (в т.ч. и Timer.OnTimer) и метода Execute дополнительного потока гарантирует то, что все исключения будут перехвачены? Среда не может выбросить исключение так сказать «между» этими процедурами?
PS: у службы нет TServiceApplication.onException. В том числе и в Delphi XE. Не знаю, почему разработчики так сделали, но видимо, были какие-то причины. Хотя есть интересный метод в protected части (DoHandleException). Но раз его туда поместили, не думаю, что простое его переопределение в наследнике что-то даст.
-
> Дело в том, что все исключения дополнительного потока Delphi > «съедает»
Чего это съедает? TThread.FatalException по завершению нити просто смотри, там все будет...
-
Зы ну и можно глобальный обработчик повесить через AddVectoredExceptionHandler
-
> через AddVectoredExceptionHandler Это что за зверь?
-
> охватывание try/except всех обработчиков (в т.ч. и Timer.OnTimer) и метода Execute
Нашиша всех-то ? Тебя же интересует глобальный перехват в каждом из потоков, включая основной ? Если так, то локальные обработчики исключений в обработчиках всякоразных событий вовсе не нужен (если на то нет явной нужды) - достаточен перехват в верхнеуровневой ф-ции/процедуре
> у службы нет TServiceApplication.onException
Так уж велика проблема сляпать его ручками по образу и подобию TApplication ?
-
-
> Rouse_ © (30.11.11 11:42) [7] Спасибо, почитаю.
-
> Зы ну и можно глобальный обработчик повесить через AddVectoredExceptionHa > ndler
Эту штуку уже пробовал использовать. Но у нее есть один недостаток (по крайней мере, для моих целей): она реагирует даже те исключения, которые могут нормально обработаться в коде. Т.е. если где-то (в моем коде или в VCL или еще где) будет блок типа: try
...
if a > 0 then rez := a
else raise Exception('');
...
except
rez := 100;
end;
то AddVectoredExceptionHandler сработает на это исключение точно так же, как и на любое другое... > достаточен перехват в верхнеуровневой ф-ции/процедуре
А где эта функция? Ведь блок begin...end в файле проекта это отдельный поток и до него не дойдет исключение из потоков служб. Или есть другая main функция для потока службы? > TThread.FatalException
Спасибо. Про это не знал. А можно как-нибудь в begin...end завернуть Run в try/except и внутри except проверить FatalException для потока службы? Т.е. я могу как-нибудь получить доступ к объекту этого потока?
-
> Спасибо. Про это не знал. А можно как-нибудь в begin...end > завернуть Run в try/except и внутри except проверить FatalException > для потока службы? Т.е. я могу как-нибудь получить доступ > к объекту этого потока?
Что-то я запутанно написал. Поэтому уточню:
try ... Application.Run; finally //Как тут проверить FatalException для потока службы? end;
-
> где эта функция?
Для основного потока - это Application.Run
Для дополнительного - это ServiceThread.Execute, в теле которого вызываются обработчики TService.OnStart/Stop/Execute
-
try ... Application.Run; finally //Как тут проверить FatalException для потока службы? тут уже никак - в этот момент потоки всех служб уже уничтожены end;
-
> Для дополнительного это ServiceThread.Execute, в теле > которого вызываются обработчики TService.OnStart/Stop/Execute
У сервиса есть FServiceThread и соответствующее свойство, доступное только для чтения. Получается, что единственный выход переписать TService и TServiceThread? Не думаю, что возьмусь за это, т.к. скорее всего, в итоге добавлю кучу глюков...
-
> единственный выход — переписать TService и TServiceThread?
Накой ? Все что нужно - завернуть в try..except тела обработчиков TService.OnStart/Stop/Execute
-
> Накой ? > Все что нужно завернуть в try..except тела обработчиков > TService.OnStart/Stop/Execute
Даже если у меня OnStart активизирует таймер? Потом же OnStart завершается, Stop еще не приходит, Execute=nil, а таймер время от времени генерирует событие OnTimer, в котором и выполняется большая часть логики программы.
-
> Execute=nil
Ну так сделай не-nil.. Там же в простейшем случае совсем незамысловатый цикл потребуется: while not Terminated do
ProcessRequests(True); // в дебрях этого метода вызывается обработчик твоего таймера Его и оберни в try..except
|