Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Система";
Текущий архив: 2004.02.06;
Скачать: [xml.tar.bz2];

Вниз

Остановка службы   Найти похожие ветки 

 
Andrew287   (2003-11-21 01:39) [0]

У меня есть служба без дополнительного потока:

procedure SService1.ServiceStart(Sender: TService; var Started: Boolean);
begin
Started := True;
end;

procedure TService1.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
ServiceThread.Terminate;
Stopped := True;
end;

procedure TService1.ServiceExecute(Sender: TService);
begin
while not Terminated do begin
// Do something
end;
end;


Работает нормально, но не удается остановить из менеджера. Растолкуйте, что куда добавить.


 
Digitman   (2003-11-21 08:16) [1]


> У меня есть служба без дополнительного потока


не соответствует действительности
все упомянутые события выполняются в контексте именно до.код.потока

procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
begin
Started := True;
end;

procedure TService1.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
Stopped := True;
end;

procedure TService1.ProcessServiceMessage(var Msg: TMessage);
begin
try
//do something
except
end;
end;

procedure TService1.ServiceExecute(Sender: TService);
var
Msg: TMsg;
begin
while not Terminated do
begin
WaitMessage;
if PeekMessage(Msg, 0, WM_SOMEMESSAGE, WM_SOMEMESSAGE, PM_REMOVE) then
ProcessServiceMessage(PMessage(@Msg.Message)^)
else
ServiceThread.ProcessRequests(False);
end;
end;


 
Andrew287   (2003-11-21 08:51) [2]

Дело в том, что информацией я обмениваюсь через Pipes в том числе и с другими компьютерами. У меня все хорошо запускается, работает и останавливается, когда оформлено с дополнительным потоком TServerThread:

procedure TNSService.ServiceStart(Sender: TService; var Started: Boolean);
begin
ServerThread := TServerThread.Create(False);
Started := True;
end;

procedure TNSService.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
ServerThread.Terminate;
Stopped := True;
end;

{ TServerThread }

procedure TServerThread.Execute;
var
Pipe: THandle;
Connected: Boolean;
Instance: TInstance;
begin
while not Terminated do begin
Pipe := CreateNamedPipe(
PipeName, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE or // message type pipe
PIPE_READMODE_MESSAGE or // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
PIPE_TIMEOUT, // client time-out
nil); // no security attribute

Connected := ConnectNamedPipe(Pipe, nil) or
(GetLastError() = ERROR_PIPE_CONNECTED);

if Connected then begin

// Do operations with Pipes

end else
CloseHandle(Pipe);
end;
end;


Вот я и не понимаю, как избавиться от TServerThread.


 
Digitman   (2003-11-21 09:50) [3]


> Дело в том, что информацией я обмениваюсь через Pipes в
> том числе и с другими компьютерами


на здоровье) ... никто и ничто этому не мешает


> Вот я и не понимаю, как избавиться от TServerThread.


в смысле ? это же - твой класс ! хочешь - создавай его экз-р, хочешь - разрушай ... кто препятствует ?

может , не от TServerThread, а от TServiceThread ? никак) ..

этот код.поток создаешь не ты и не тебе его уничтожать
здесь ты обязан придерживаться строгого правила :

если ты не назначил обработчик события TService.OnExecute, то заботиться об обработке команд, передаваемых системным сервис-менеджером твоему сервису (старт, стоп, пауза, шатдаун и т.д.) не нужно - это сделает само твое приложение-сервис

если же ты таки обрабатываешь событие TService.OnExecute, то в его обработчике ты обязан периодически вызывать метод ServiceThread.ProcessRequest(False), причем период вызова должен быть насколько это возможно минимальным, дабы сервис быстрее реагировал на команды системного сервис-менеджера, иначе твой сервис будет реагировать на них лишь после завершения обработчика TService.OnExecute


 
Digitman   (2003-11-21 10:01) [4]

примерное правило таково :
- если ты работаешь с пайп-сервером в блокирующем режиме, то лучше всего организовать эту работу в своем доп.код.потоке и не обрабатывать никак TService.OnExecute, либо работать с блок.пайп-сервером в обработчике TService.OnExecute, но с использованием миним.таймаутов приема/передачи, по истечении которых обязательно вызывать ServiceThread.ProcessRequest(False) и тут же проверять св-во ServiceThread.Terminated - сигнал к немедленному закруглению твоего пайп-хозяйства и завершению работы сервиса

- если ты работаешь с пайп-сервером в НЕблокирующем режиме (overlapped-режим), то TService.OnExecute так же можно не обрабатывать, просто создать/активировать пайп-сервер в событии OnStart и деактивировать/уничтожать его в событии OnStop.. трансп.события же самого пайп-сервера будут вызываться асинхронно, как overlapped-процедуры, тебе лишь следует указать overlapped-обработчики соотв.событий пайп.сервера


 
Andrew287   (2003-11-21 10:01) [5]

>Digitman © (21.11.03 09:50) [3]

Я подумал над твоим ServiceExecute и понял, что своим ожиданием подключения к Pipe я останавливал основной и единственный поток службы. Проще всего создавать новый поток и в нем ждать.

Спасибо.


 
Digitman   (2003-11-21 10:31) [6]


> Проще всего создавать новый поток и в нем ждать


учти, что если в этом новом потоке ты будешь бесконечно ждать трансп.событий пайп-сервера, то ты не сможешь отреагировать вовремя на Terminate твоего потока, и сервис опять же не сможет быть остановлен, ибо корректно остановленным он будет считаться когда твой код.поток завершит работу по команде Terminate (а он в это время озабочен лишь одним : бесконечно ждет трансп.событий)

опять же (неважно в каком код.потоке) - либо блок.режим и короткие тайм-ауты ожидания тр.событий либо overlapped-режим пайп-сервера... третьего не дано)


 
Andrew287   (2003-11-21 10:40) [7]

Нет, по Terminate функция ConnectNamedPipe сразу прерывается, поток завершается и никаких проблем.


 
Andrew287   (2003-11-21 10:53) [8]

Кстати, у меня не получилось отлаживать службу. Сделал все, как в хелпе, прописал путь к Delphi в реестре. Запускаю службу - начинает грузиться Delphi, но все прерывается с какими-то сообщениями, а в среде - пустой проект. Есть рекомендации?


 
Digitman   (2003-11-21 10:58) [9]


> по Terminate функция ConnectNamedPipe сразу прерывается


да ничего подобного !

с какой, спрашивается, стати выполняющаяся ф-ция должна "прерваться" ?

читаем сюда (внимательнейшим образом !!)

If hNamedPipe was not opened with FILE_FLAG_OVERLAPPED and lpOverlapped is NULL, the function does not return until a client is connected or an error occurs. Successful synchronous operations result in the function returning TRUE if a client connects after the function is called. If a client connects before the function is called, the function returns FALSE and GetLastError returns ERROR_PIPE_CONNECTED. This can happen if a client connects in the interval between the call to CreateNamedPipe and the call to ConnectNamedPipe. In this situation, there is a good connection between client and server, even though the function returns FALSE.

If hNamedPipe was not opened with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the operation executes asynchronously. The function returns immediately with a return value of FALSE. If a client process connects before the function is called, GetLastError returns ERROR_PIPE_CONNECTED. Otherwise, GetLastError returns ERROR_IO_PENDING, which indicates that the operation is executing in the background. When this happens, the event object in the OVERLAPPED structure is set to the nonsignaled state before ConnectNamedPipe returns, and it is set to the signaled state when a client connects to this instance of the pipe.

The server process can use any of the wait functions or SleepEx


 
Andrew287   (2003-11-21 11:07) [10]

Я ничего не придумываю. Попробуй мой текст - увидешь, что функция прерывается. Лучше помоги с отладкой.


 
Digitman   (2003-11-21 11:31) [11]


> Попробуй мой текст


и даже пробовать не буду.

потому что никакую ф-цию никаким образом прервать нельзя

пока ф-ция сама не завершится (читай - не сделает все что ей положено делать при ее вызове с такими-то параметрами и при таких-то начальных условиях), все что следует за ее вызовом выполнено не будет.

а теперь представь себе, что клиенты твоего пайп-сервера "молчат"
поскольку пайп-сервер инициирован для работы в блок.режиме (PIPE_WAIT не я написал, а ты сам)
ф-ция ConnectNamedPipe , будучи вызванная в этом случае, будеть "вешать" твой код.поток на неопределенно долгое время (пока хотя бы один клиент не сподобится "заговорить" с сервером)

не знаю уж, чему у тебя там равно значение PIPE_TIMEOUT, но задал ты его бестолково, потому что WaitNamedPipe() ты все равно не используешь.

p.s.
здесь не говорим о TerminateThread() - это из другой оперы


 
Andrew287   (2003-11-21 11:41) [12]

const
PIPE_TIMEOUT = NMPWAIT_USE_DEFAULT_WAIT;

Прерывается, однако. Лень исследовать, но думаю, в функции происходит исключение.


 
Digitman   (2003-11-21 11:55) [13]


> Прерывается, однако


не выдумывай.
не "прерывается", а благополучно (с ошибкой или без нее) завершает свое выполнение и возвращает тебе управление


> Лень исследовать, но думаю, в функции происходит исключение


тоже не выдумывай ! никаких исключений там не происходит

читаем хэлп на параметр nDefaultTimeOut ф-ции CreateNamedPipe:

Specifies the default time-out value, in milliseconds, if the WaitNamedPipe function specifies NMPWAIT_USE_DEFAULT_WAIT. Each instance of a named pipe must specify the same value.

ты что задал в кач-ве значения ? ноль ? т.е. не ждать нисколько ? вот она, ф-ция ConnectNamedPipe(), и не ждет ничего, а сразу завершается, если кл.запросов на коннект нет в момент ее вызова !

и тебе черным по белому написано в хэлпе : константа NMPWAIT_USE_DEFAULT_WAIT = 0 должна передаваться параметром не в ф-цию CreateNamedPipe(), а в WaitNamedPipe(), и при этом за величину тайм-аута ф-ция WaitNamedPipe() возьмет то значение, которое ты передал параметром в CreateNamedPipe()... а ты туда ноль влупил ! вот и создается у тебя "иллюзия прерывания"))


 
Andrew287   (2003-11-21 12:35) [14]

Правильно все говоришь. Я безответственно подошел к выдиранию кусков из хелпа. Скажи что-нибудь по поводу [8].


 
Digitman   (2003-11-21 15:52) [15]

простейший вариант - вывод сообщение MessageBox(0, ...) в контр.точках


 
Digitman   (2003-11-21 16:07) [16]

другой надежный вариант - метод TService.LogMessage()


 
Varfolomey   (2003-11-23 02:48) [17]

Намыльте мне кто небуть примерчет с сервисами ПЛЗ!



Страницы: 1 вся ветка

Форум: "Система";
Текущий архив: 2004.02.06;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.49 MB
Время: 0.033 c
1-16311
Lisa
2004-01-25 16:44
2004.02.06
TDBNavigator


14-16707
Maxim Vetera
2004-01-16 19:06
2004.02.06
Мeteorite!!!


4-16823
igornov
2003-11-13 16:22
2004.02.06
Как заставить нормально работать delphi- сервис при log of и on


3-16158
Вованчик
2004-01-14 10:37
2004.02.06
SELECT


1-16213
Zergling
2004-01-28 08:43
2004.02.06
EInvalidOp :0( - (ошибка при операциях с плавающей точкой)





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский