-
WaitNamedPipe нагружает процессор до 99% на сервере под управлением Win Server 2003. Без использования этой функции все работает нормльно. Подскажите в чем сожет быть дело? В коде клиента фрагмент который закомментирован нагружает процессор, ниже этого фрагмента код без использования WaitNamedPipe работает без проблем. Код сервера: procedure TPipeThread.Execute;
var
hServiceInfoPipe, hThread: THandle;
ServiceInfoPipeName: PWideChar;
ServiceInfoPipeConnected: Boolean;
dwThreadId, dwBytesRead: DWORD;
begin
ServiceInfoPipeName:=PWideChar('\\.\PIPE\MyPipe');
ServiceInfoPipeConnected:=False;
dwThreadId:=0;
hServiceInfoPipe:=INVALID_HANDLE_VALUE;
hThread:=0;
while True do
begin
hServiceInfoPipe:=CreateNamedPipe(
ServiceInfoPipeName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE or PIPE_READMODE_MESSAGE or PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, SizeOf(TServiceInfoPipeData), SizeOf(TServiceInfoPipeData), 0, nil); if hServiceInfoPipe = INVALID_HANDLE_VALUE then Continue;
ServiceInfoPipeConnected:=ConnectNamedPipe(hServiceInfoPipe, nil);
if GetLastError=ERROR_PIPE_CONNECTED then ServiceInfoPipeConnected:=True;
if ServiceInfoPipeConnected then
begin
hThread := CreateThread(
nil, 0, @ServiceInfoProcessing, LPVOID(hServiceInfoPipe), 0, dwThreadId); if hThread=0 then
begin
CloseHandle(hServiceInfoPipe);
Continue;
end else CloseHandle(hThread);
end else CloseHandle(hServiceInfoPipe);
end;
end; Код клиента: procedure SendInfoToPipe(const ServiceEvent: Byte;
ResultInfoStr: string);
var
ServiceInfoPipeName: PWideChar;
hServiceInfoPipe: THandle;
SrvInfoPipeData: TServiceInfoPipeData;
cbWritten, dwMode: DWORD;
fSuccess: Boolean;
begin
ServiceInfoPipeName:=PWideChar('\\.\PIPE\MyPipe');
fSuccess:=False;
with SrvInfoPipeData do
begin
EventCode:=ServiceEvent;
ServiceResultInfo:=ResultInfoStr;
EventDate:=Date;
end;
hServiceInfoPipe := CreateFile(
ServiceInfoPipeName, GENERIC_READ or GENERIC_WRITE,
0, nil, OPEN_EXISTING, 0, 0); if hServiceInfoPipe = INVALID_HANDLE_VALUE then Exit;
dwMode:=PIPE_READMODE_MESSAGE;
fSuccess:=SetNamedPipeHandleState(
hServiceInfoPipe, dwMode, nil, nil); // don't set maximum time
if not fSuccess then Exit;
fSuccess:=WriteFile(hServiceInfoPipe, SrvInfoPipeData, SizeOf(TServiceInfoPipeData),
cbWritten, nil);
CloseHandle(hServiceInfoPipe);
end;
-
> нагружает процессор
Все то время пока она ждет ? Не верю.
-
> Все то время пока она ждет ? > Не верю.
Но это так! Клиентом является служба, а сервером приложение. И все, на первый взгляд, работает как положено - сообщения отправляются и принимаются, но в диспечере задач процесс клиента постепенно нагружает процессор.
-
Еще замечу, что на WinXPx86, Win7x64, WinServer2008 работает нормально, а на 2-х серверах WinServer2003 наблюдается вышеописанный глюк.
-
> [0] Madlinx (26.01.12 17:42)
откуда такой вывод? чем заняты другие потоки?
-
Последовательность NamedPipeAPI-вызовов на клиентской стороне у тебя вообще с ног на голову поставлена.
Должно быть WaitNamedPipe -> CreateFile, а у тебя наоборот CreateFile -> WaitNamedPipe.
Цитата из справки к WaitNamedPipe :
If the function succeeds, the process should use the CreateFile function to open a handle to the named pipe. A return value of TRUE indicates that there is at least one instance of the pipe available
-
> Должно быть WaitNamedPipe -> CreateFile
Не обязательно. Вообще это мой первый опыт работы с каналами и делал я все по примеру на сайте MSDN: Многопоточный сервер: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365588(v=vs.85).aspx И клиент к нему: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365592(v=vs.85).aspx У меня у клиента реализовано так же, а именно: 1. Пытаюсь подключиться к каналу. 2. Если подключился, то выхожу из цикла и произвожу запись. 3. Если не подключился, то, если последняя ошибка не ERROR_PIPE_BUSY (ОШИБКА_КАНАЛ_ЗАНЯТ) то выходим из процедуры. 4. Если последняя ошибка ERROR_PIPE_BUSY (ОШИБКА_КАНАЛ_ЗАНЯТ) то ожидаем особождения канала и, если дождались, опять входим в цикл и возвращаемся к пункту 1 для повтора подключения к каналу.
-
> чем заняты другие потоки?
В потоках созданных сервером происходит следующее (пример чисто схематический) case InfoCode of 1: ShowBaloonHint; //Всплывающее сообщение с текстом "1" 2: ShowBaloonHint; //Всплывающее сообщение с текстом "2" 3: ShowBaloonHint; //Всплывающее сообщение с текстом "3" end;
-
> Madlinx (27.01.12 10:00) [6] > Не обязательно
Что значит "не обязательно" ? Накой шиш тогда вообще вызывать WaitNamedPipe, если следом за ним не вызывать CreateFile ? Ведь WaitNamedPipe по сути нужна для обнаружения клиентом в интересующем его промежутке времени факта создания сервером экз-ра именованого канала. А зачем, спрашивается, его вообще обнаруживать, если не для последующего подключения к нему и использования ?
Иными словами, вызов WaitNamedPipe не обязателен к использованию, но если он клиентом таки был сделан, то именно для того чтобы минимизировать вероятность отказа последующего вызова CreateFile.
К тому же, если уж сервером при CreateNamedPipe в параметре nDefaultTimeOut указан 0, то вызов клиентом WaitNamedPipe c параметром nTimeOut = NMPWAIT_USE_DEFAULT_WAIT лишен смысла - ф-ция попросту немедленно вернет управление с результатом FALSE, если на момент вызова свободный и готовый для подключения экз-р канала не существует.
> В потоках созданных сервером
Сервер-то причем ? Коль скоро речь идет о WaitNamedPipe, то идет она именно о процессе клиента, а не сервера. Сервер НЕ использует WaitNamedPipe.
-
> Накой шиш тогда вообще вызывать WaitNamedPipe, если следом > за ним не вызывать CreateFile ?
Так CreateFile у меня и вызывается после WaitNamedPipe, когда цикл идет на второй круг после неудачной попытки подключения "с лету" (при входе в цикл) к занятому каналу.
> К тому же, если уж сервером при CreateNamedPipe в параметре > nDefaultTimeOut указан 0, то вызов клиентом WaitNamedPipe > c параметром nTimeOut = NMPWAIT_USE_DEFAULT_WAIT лишен > смысла
Параметр 0 в CreateNamedPipe означает, что будет использовано значение по умолчанию, а это 50 мс. Выдержка из справки MSDN: A value of zero will result in a default time-out of 50 milliseconds.
-
> делал я все по примеру на сайте MSDN..клиент к нему
Ну так там же, в примере, последовательность вызовов не менее очевидна ..
while True do begin if CreateFile(..)=ВалидныйХедндлКанала then Break; // выход из цикла - первая же (безо всякого ожидания) или последующая (после ожидания) попытка подключения прошла успешно .. // не удалось подключиться, подождем пока канал будет создан или сервер будет свободен if not WaitNamedPipe(..) then Exit; // канал по прежнему не существует или сервер занят - подключаться к нему бессмысленно, поэтому выходим из подпрограммы, хотя по-хорошему следовало бы уточнить причину отказа анализом GetLastError .. иначе идем в начало тела цикла, где пытаемся повторно подключиться к каналу end; .. здесь можно пользовать канал
-
> CreateFile у меня и вызывается после WaitNamedPipe, когда > цикл идет на второй круг
А, ну да .. while-цикл у тебя в закомментаренном коде я проглядел .. Тогда с последовательностью вызовов у тебя порядок.
А вот с дифолтным таймаутом - беда. Поскольку WaitNamedPipe у тебя вообще ничего не ждет, ее вызывающий поток все то время, пока крутится while-цикл, находится в user-time, не переходя в kernel-time. Вот потому-то ты и видишь повышенную "нагрузку". И в этой ситуации странным выглядит поведение не Win Server 2003, а как раз иных ОС, где нет сколь-либо ощитумого роста нагрузки.
-
> А вот с дифолтным таймаутом - беда.
Т.е. нужно на сервере и на клиенте в таймаут выставить конкретные значения, например 1000?
-
На клиенте нельзя указать конкретное значение таймаута ожидания.
Можно лишь указать NMPWAIT_WAIT_FOREVER (ждать до потери пульса) либо NMPWAIT_USE_DEFAULT_WAIT (ждать столько сколько сервер при CreateNamedPipe указал в nDefaultTimeOut)
-
Все понял, попробую и отпишусь. Но это только завтра, когда буду на работе. Спасибо.
-
Не помогло. К сожалению проблема осталась. Решил оставить без WaitNamedPipe
-
Т.е. ты у тверждаешь что при NMPWAIT_WAIT_FOREVER бесконечно ждущая при этом WaitNamedPipe в однопоточном клиентском процессе приводит к картине с ощутимым ростом нагрузки на CPU для данного потока этого процесса, так ?
-
Значит так, обнаружилось еще кое что... Клиентское приложение у меня в 2 независимых потока обрабатывает файлы (открепляет и прикрепляет файлы к/от сообщений Novel GroupWise). Было замечено, что проблема возникает только когда работает поток открепления файлов и даже в том случае, если запись в канал из этого потока не производится. Т.е. если работает этот поток и используется WaitNamedPipe , то проблемя существует, а если WaitNamedPipe не используется, то проблемы нет (замечу что даже в том случае, когда из этого потока в канал не производится). У меня есть подозрения, что в этом как-то замешан цикл while ... do ... используемый в потоке. В этом цикле обрабатывается строка, например, TestString while Pos(',',TestString)>0 do TestString[Pos(',',TestString)]:=#13; Почему я подозреваю этот цикл? Потому что в обоих потоках код, в принципе, аналогичен, за исключением вышеописанного цикла, который во втором потоке используется в 4 местах.
-
Значит так: никакие потоки кроме того в котором осуществляется вызов WaitNamedPipe никого сейчас не интересуют и должны быть исключены из рассмотрения, ибо вопрос быз задан конкретно о WaitNamedPipe.
Посему без ответа на вопрос в [16] дальнейшие рассуждения на эту тему бессмысленны.
-
Все ведь просто выясняется:
Делаешь два простейших тестовых проекта - сервера и клиента. Можно даже сделать их консольными.
В серверном приложении в одном единственном потоке вызываешь CreateNamedPipe и следом же усыпляешь этот поток по Sleep(INFINITE)
В клиентском приложении в одном единственном потоке вызываешь единственную ф-цию WaitNamedPipe с NMPWAIT_WAIT_FOREVER
Стартуешь первым сервер, затем клиент.
Идешь в диспетчер задач и смотришь на CPU-нагрузку клиента.
Проделываешь все это на всех интересующих ОС, результаты в табличном виде приводишь сюда.
|