![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Помогите разобраться с потоками в сервисе
jcl © (2016-08-25 15:49:00)Добрый день!
Тема со службами и с потоками для меня новая, поэтому вышла путаница.
Для создания службы использую стандартный Service Application (все делаю на примере http://www.tolderlund.eu/delphi/service/service.htm). Добавляю обработчики событий onStart, onStop и onShutDown. В обработчике onStart создают первый поток, а в его методе Execute делаю бесконечный цикл, пока не Terminated. Собственно код стандартный. Теперь мне нужно сделать несколько потоков (на чтение входящих документов, на отправку квитанции о доставке, на запись исходящих документов, на получение квитанций о регистрации документа). Вопрос: в каком месте это следует сделать так, чтобы службу не посчитали умершей (т.к. предполагается обращение к базе, работа с данными)? в методе onStart службы (где, собственно первый поток и создается) или в методе Execute первого потока? И еще вопросы: как лучше построить иерархию классов потоков: один родительский поток с виртуальными методами, а от него наследовать и переопределять или тупо создать несколько классов потоков?
И еще: логирование посредством Log4D следует сделать тоже отдельным потоком или просто из рабочих вызывать? Если отдельным, то как передавать управление?
Не ругайте слишком сильно, материал для меня оказался сложным и в посмотрев примеры в инете не уложилось....
Спасибо!!!
P.S. использую D2007
Тимохов Дима (2016-09-25 22:43:00) [1]
> sniknik © (30.08.16 16:32) [22]
> > Впредь буду писать без стандартных классов, но на этапе
> обучения не получилось без них обойтись.
> :) я делал наоборот... чтобы разобраться/обучится писал
> сервис на winapi, а после с использованием стандартных классов.
> они ведь чисто для удобства/скорости написания нужны, а
> не для обучения. ИМХО конечно.
Поддерживаю полностью.
Сначала надо суть понять.
А потом можно и классы стандартные использовать.
Игорь Шевченко (2016-08-31 23:08:00) [2]Eraser © (31.08.16 20:26) [23]
> как оно может быть не расширяемо, если оно на чистом API
Вот поэтому и не расширяемо. Если бы был написан набор классов, то расширяемо, а портянка на API - я бы и рекомендовать не стал. И да, за свой древний пример по Named pipes мне тоже стыдно :)
Eraser (2016-08-31 20:26:00) [3]
> Игорь Шевченко © (30.08.16 11:09) [20]
как оно может быть не расширяемо, если оно на чистом API, расширять можно на сколько фантазии хватит.
а вот стандартный класс спроектирован плохо и не расширяем. автор очень уж побаивался ключевого слова virtual.
не поленился полез посмотреть, что конкретно там не устраивало. надеялся может лет за 10 что-нибудь переписал. не переписали.
там проблема в самом сердце класса:
procedure TService.Main(Argc: DWord; Argv: PLPWSTR);
type
PPCharArray = ^TPCharArray;
TPCharArray = array [0..1024] of PChar;
var
i: Integer;
Controller: THandlerFunction;
begin
for i := 0 to Argc - 1 do
FParams.Add(PPCharArray(Argv)[i]);
Controller := GetServiceController();
FStatusHandle := RegisterServiceCtrlHandler(PChar(Name), @Controller);
if (FStatusHandle = 0) then
LogMessage(SysErrorMessage(GetLastError))
else
DoStart;
end;
это обычный, не виртуальный метод.
автор не слышал про существование RegisterServiceCtrlHandlerEx. т.о. мы можем обрабатывать только коды управления времен win2K, все что появилось позже не поддерживается.
+ была проблема с назначением описания к службе.
> jcl (30.08.16 15:49) [21]
> Впредь буду писать без стандартных классов
тут надо понимать, что в целом, я против такого подхода изобретения велосипедов. в конкретно взятом случае с сервисом свой велосипед, на основе той ссылки, будет грамотней и функциональнее.
sniknik (2016-08-30 16:32:00) [4]> Впредь буду писать без стандартных классов, но на этапе обучения не получилось без них обойтись.
:) я делал наоборот... чтобы разобраться/обучится писал сервис на winapi, а после с использованием стандартных классов. они ведь чисто для удобства/скорости написания нужны, а не для обучения. ИМХО конечно.
jcl (2016-08-30 15:49:00) [5]
> Eraser © (30.08.16 01:16) [19]
Спасибо большое, посмотрю.
> понадобится из сервиса перехватывать факт выхода/входа пользователя
> в систему
Для этого сервиса впринципе такой задачи не может быть поставлено. Впредь буду писать без стандартных классов, но на этапе обучения не получилось без них обойтись.
Игорь Шевченко (2016-08-30 11:09:00) [6]Eraser © (30.08.16 01:16) [19]
> хороший пример базового сервиса есть у Розыча http://rouse.
> drkb.ru/winapi.php#twoservicedemo
> абсолютно ничего сложно там нет.
Там все чрезмерно запутано и нерасширяемо вообще.
Eraser (2016-08-30 01:16:00) [7]
> jcl (25.08.16 15:49)
Эх, по ряду причин, настоятельно рекомендую не использовать стандартные VCL классы для реализации сервиса. Там все чрезмерно запутанно и плохо расширяемо. Закончится все копированием исходников SvcMgr в папку с проектом и правкой. Вот, к примеру, понадобится из сервиса перехватывать факт выхода/входа пользователя в систему.
Этот тот редкий случай, когда нужно писать с нуля. Там все не так сложно, как кажется, хороший пример базового сервиса есть у Розыча http://rouse.drkb.ru/winapi.php#twoservicedemo
абсолютно ничего сложно там нет.
jcl (2016-08-29 17:21:00) [8]Проблема решилась, спасибо iop.
был сделан метод Execute у службы, в него добавлен
MyServiceThread := TMyServiceThread.Create;
MyServiceThread.Resume;
While NOT Terminated do
Begin
ServiceThread.ProcessRequests(true);
End;
На тему True или False есть обсуждение http://www.sql.ru/forum/690236/prostenkiy-servis-cpu-usage-51-chto-posovetuete
А в procedure TMyServiceThread.Execute; добавить полезный код.
Еще полезная ссылка http://delphi.xcjc.net/viewthread.php?tid=48065
jcl (2016-08-29 16:25:00) [9]
> iop © (29.08.16 16:18) [16]
А если без сарказма, нормально объяснить?
iop (2016-08-29 16:18:00) [10]Пытаюсь сделать второй вариант
ну и как? получается?
ps читать надо не левые статьи на королевствах, а документацию.
jcl (2016-08-29 16:08:00) [11]Пытаюсь сделать второй вариант
jcl (2016-08-29 16:08:00) [12]
> iop © (29.08.16 15:58) [13]
> сервис делает всю свою полезную работу в своем онЭкзекуте
Вырезка из статьи на Королевстве:
Вы можете реализовать работу службы двумя способами.
Вариант первый: стартует служба, вы начинаете что-то делать, время от времени уведомляя систему о своём состоянии, потом служба останавливается.
Вариант второй: стартует служба, создаёт рабочие потоки. По уведомлению от системы потоки останавливаются и служба выключается.
Обычно в службах используется второй вариант, но это ваш выбор — мы расскажем об обоих.
Для второго варианта реализации вы не должны назначать обработчик OnExecute, но обязаны реализовать, как минимум, OnStart и OnStop. В первом обработчике вы запускаете рабочие потоки службы, а в OnStop — останавливаете
Так в чем ошибка то?
iop (2016-08-29 15:58:00) [13]сервис делает всю свою полезную работу в своем онЭкзекуте
и этот онЭкзекут выполняется не в той нити что криэйт и старт.
jcl (2016-08-29 15:32:00) [14]
> iop © (29.08.16 15:22) [10]
То есть, вы предлагаете перенести цикл в onStart сервиса, а в Thread просто выполнять полезную работу?
jcl (2016-08-29 15:29:00) [15]
> iop © (29.08.16 15:16) [9]
Это здесь неправильно?
procedure TDirectum_Integration.ServiceStart
....
MyServiceThread.Resume;
Так было в примере в статье. А откуда надо вызывать?
> iop © (29.08.16 15:22) [10]
Тут что не так?
iop (2016-08-29 15:22:00) [16]а еще наивно надеяться что в нитке это будет "тикать" раз в секунду.
Sleep(1000);
iop (2016-08-29 15:16:00) [17]из неправильного места вызвал создание своей нитки
jcl (2016-08-29 15:01:00) [18]
> sniknik © (29.08.16 13:32) [7]
Это при создании Thread Object было задано имя. Ну можно и убрать. просто хотелось посмотреть, что это такое.
У меня еще вопрос. Весь полезный код находится в OnExecute у Thread. А он не выполняется! Был помещен туда код лога после
if Count >= SecBetweenRuns then
begin
Count := 0;
И не работает. В чем может быть ошибка?
sniknik (2016-08-29 13:32:00) [19]а вот это вот нафига?
> procedure TMyServiceThread.SetName;
> ...
> end;
без имени у потока не обойтись? насколько знаю только для скриптовых языков/вставок нужно, внутри же найтивного кода излишество, всегда можно по объекту напрямую работать.
p.s. может просто не знаю и есть какой тайный смысл? (не считая функций поиска объекта по имени, которые практически не используются)
jcl (2016-08-29 13:02:00) [20]Ахаха!! Спасибо!!!