![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Проблема с потоками [D7, XP]
Buzzik © (2010-04-06 18:56:00)Пишу программу, для проверки работоспособности большого количества комутаторов, по средством пинг. Чтобы приложение не подвисало начал использовать потоки. И все бы хорошо, если опрашиваемых комутаторов не много, но если их около сотни и больше, и многии из них лежат, то когда идет ожидание ответа - программа начинает подвисать. Причем загрузка проца около 10%-15%.
в procedure TNewThread.Execute;
у меня идет стандартная посылка пакета
IcmpSendEcho(hIP,
destAddress.S_addr,
@pingBuffer,
sizeof(pingBuffer),
Nil,
pIpe,
sizeof(icmp_echo_reply) + sizeof(pingBuffer),
Timeout);
и результат идет вSynchronize(UpdateGrid);
В которой собственно изменения идут в vlc.
По таймеру у меня идет запуск цикла потоков
if tr_on_=false then //Проверяю закончился ли прошлый
//таймерный цикл
for i:=0 to form1.NextGrid1.RowCount-1 do
begin
if form1.NextGrid1.CellByName['Enabled',i].AsBoolean=true then begin
Delay(1);
Application.ProcessMessages;
host_2:= form1.NextGrid1.CellByName['IP',i].AsString;
colgrid:=i;
NewThread:=TNewThread.Create(true);
NewThread.FreeOnTerminate:=true;
NewThread.Priority:=tpLower;
NewThread.Resume;
// delay(10);
end;
Скорее всего подвисание происходит когда выполняетьсяIcmpSendEcho, пакет не проходит и идет собственноTimeout.
Подскажите, пожалуйста как избежать подвисания интерфейса программы.
Или как правильно организовать работу данной задачи.
Buzzik (2010-04-07 11:55:00) [1]
> DVM
Спасибо, помогло, работает без тормозов, хоть я и не дошел до сообщений.
Всем спасибо, за помощь в решении проблемы.
Slym (2010-04-07 10:57:00) [2]Удалено модератором
Loginov Dmitry (2010-04-06 23:22:00) [3]Вот что хотелось бы добавить:
Synchronize(UpdateGrid);
следует убрать.
Если 100 потоков почти одновременно его вызовут, тормозища будут страшные (причем и потоки будут висеть - друг друга ждать). Вместо этого следует разработать структуру для временного хранения полученных данных.
Бросить на форму таймер, который будет несколько раз в секунду считывать информацию их этой структуры и отображать ее на сетке. При этом структура должна быть "потокобезопасной". Плюс все это можно неслабо оптимизировать (например не обновлять ячейку, если ее значение не изменилось).
Дмитрий Белькевич (2010-04-06 23:02:00) [4]
> with напиши. Глаза болят.
Да и вообще - к форме из треда лучше не лезть. Пусть форма сообщения от тредов обрабатывает.
Но with напиши даже в форме.
И вот это: CellByName['Kol_vo_p',vi_] лучше один раз посчитать как-то типа CellKolVol := CellByName['Kol_vo_p',vi_] (если, правда, CellByName возвращает какой-нибудь TCell) и уже потом по всему методу к CellKolVol обращаться.
Как есть - больно глазам и компьютеру.
Дмитрий Белькевич (2010-04-06 22:53:00) [5]>form1.NextGrid1
with напиши. Глаза болят.
DVM (2010-04-06 21:01:00) [6]
> Buzzik © (06.04.10 20:49) [5]
> > DVM
> Может быть, просто замеченно что именно в том месте подвисает.
> Покопаю в этом направлении.
Ты лучше сделай по другому.
1) Выкинь таймер, не нужен он.
2) Создаешь нужное число потоков по числу коммутаторов.
3) Циклы делаешь в самих потоках.
4) Пусть потоки извещают главный поток с помощью сообщений
Buzzik (2010-04-06 20:49:00) [7]
> DVM
Может быть, просто замеченно что именно в том месте подвисает.
Покопаю в этом направлении.
> Игорь Шевченко
Проверено опытным путем, что если закаментить весь вывод, то подвисание всеравно происходит
procedure TNewThread.UpdateGrid;
var //i, j:integer;
str:string;
begin
if (pos('Reqested Timed out.', msg)=0)and(pos('Destination host unreachable.', msg)=0) then begin
if form1.NextGrid1.CellByName['Status',vi_].AsString='Down' then
form1.NextGrid1.CellByName['Log',vi_].AsString:=
datetimetostr(now)+' '+form1.NextGrid1.CellByName['IP',vi_].AsString
+' is UP'+#13+
form1.NextGrid1.CellByName['Log',vi_].AsString;
form1.NextGrid1.CellByName['Status',vi_].AsString:='OK';
form1.NextGrid1.CellByName['Status', vi_].Color:=clWhite;
form1.NextGrid1.CellByName['Kol_vo_p',vi_].AsInteger:=0;
end else Begin
form1.NextGrid1.CellByName['Kol_vo_p',vi_].AsInteger:=
form1.NextGrid1.CellByName['Kol_vo_p',vi_].AsInteger+1;
if (form1.NextGrid1.CellByName['Status',vi_].AsString='OK')or
(form1.NextGrid1.CellByName['Status',vi_].AsString='Unknown')or
(form1.NextGrid1.CellByName['Status',vi_].AsString='Disabled')
then begin
form1.NextGrid1.CellByName['Status',vi_].AsString:='Some problems';
form1.NextGrid1.CellByName['Status', vi_].Color:=clYellow;
end;
if (form1.NextGrid1.CellByName['Kol_vo_p',vi_].AsInteger>form1.ploss_spin.value-1)
then begin
if form1.NextGrid1.CellByName['Status',vi_].AsString='Some problems' then
if form1.NextGrid1.CellByName['Kol_vo_p',vi_].AsInteger=form1.ploss_spin.value then begin
form1.NextGrid1.CellByName['Status',vi_].AsString:='Down';
form1.NextGrid1.CellByName['Status', vi_].Color:=clRed;
form1.NextGrid1.CellByName['Log',vi_].AsString:=
datetimetostr(now)+' '+form1.NextGrid1.CellByName['IP',vi_].AsString
+' is DOWN'+#13+
form1.NextGrid1.CellByName['Log',vi_].AsString;
if Form1.Alert_CheckBox.Checked=true then
if Alert_window.Visible=false then begin
ShowWindow(Alert_window.Handle, SW_RESTORE);
row_down:=vi_;
Alert_window.timer2.Enabled:=true;
Alert_window.Label1.Caption:=
form1.NextGrid1.CellByName['Host',vi_].AsString+' is DOWN'+#13;
//+
end; end;
if form1.NextGrid1.CellByName['Alarm_en', vi_].AsBoolean=true then
begin
if form1.NextGrid1.CellByName['Kol_vo_p',vi_].AsInteger=form1.ploss_spin.value then begin
str:=(form1.NextGrid1.CellByName['Alarm', vi_].AsString);
if BASS_ChannelIsActive(Channel)<>BASS_ACTIVE_PLAYING then
if mute<>true then begin
try
BASS_ChannelStop(Channel);
Channel := BASS_StreamCreateFile(FALSE, PChar(str), 0, 0, 0);
if form1.NextGrid1.CellByName['Loop_sound', vi_].AsBoolean<>false then
BASS_ChannelFlags(channel, BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP) // set LOOP flag
else
BASS_ChannelFlags(channel, 0, BASS_SAMPLE_LOOP); // remove LOOP flag
BASS_ChannelPlay(Channel, true);
except end;
end;
end;
end;
end;
end;
if form1.NextGrid1.CellByName['Enabled',vi_].AsBoolean=false
then form1.NextGrid1.CellByName['Status',vi_].Color:=clGray;
tr_on_:=false;
end;
Игорь Шевченко (2010-04-06 20:28:00) [8]
> Synchronize(UpdateGrid);
еще эту часть - UpdateGrid
DVM (2010-04-06 20:23:00) [9]
> Buzzik ©
она у тебя виснет не потому что коммутаторы недоступны, а потому что ты постоянно создаешь разрушаешь потоки.
Нахрена их уничтожать то?
Buzzik (2010-04-06 20:08:00) [10]
procedure TNewThread.Execute;
var
hIP : THandle;
pingBuffer : array [0..31] of Char;
pIpe : ^icmp_echo_reply;
wVersionRequested : WORD;
lwsaData : WSAData;
error : DWORD;
destAddress : In_Addr;
// i: integer;
IPReply: string; pHostEn : PHostEnt;
begin
// delay(100);
tr_on_:=true;
vi_:=colgrid;
msg:='';
host_:=host_2;
hIP := IcmpCreateFile();
pHostEn := gethostbyname(pchar(host_));
if not Assigned(pHostEn) then
begin
msg := 'Reqested Timed out.';
Synchronize(UpdateGrid); Exit;
end;
destAddress := PInAddr(pHostEn^.h_addr_list^)^;
GetMem( pIpe,
sizeof(icmp_echo_reply) + sizeof(pingBuffer));
pIpe.Data := @pingBuffer;
pIpe.DataSize := sizeof(pingBuffer);
wVersionRequested := MakeWord(1,1);
error := WSAStartup(wVersionRequested,lwsaData);
if (error <> 0) then
begin
msg := 'Reqested Timed out.';
end;
msg3:= IntToStr(LoByte(LoWord(pIpe^.Address)))+'.'+
IntToStr(HiByte(LoWord(pIpe^.Address)))+'.'+
IntToStr(LoByte(HiWord(pIpe^.Address)))+'.'+
IntToStr(HiByte(HiWord(pIpe^.Address)));
Timeout:=(2000);
//CriticalSection.Enter;
if error=0 then begin
IcmpSendEcho(hIP,
destAddress.S_addr,
@pingBuffer,
sizeof(pingBuffer),
Nil,
pIpe,
sizeof(icmp_echo_reply) + sizeof(pingBuffer),
Timeout);
end;
// CriticalSection.Leave;
error := GetLastError();
if (error <> 0) then
begin
msg := 'Reqested Timed out.';
end;
if error=0 then begin
IPReply := IntToStr(LoByte(LoWord(pIpe^.Address)))+'.'+
IntToStr(HiByte(LoWord(pIpe^.Address)))+'.'+
IntToStr(LoByte(HiWord(pIpe^.Address)))+'.'+
IntToStr(HiByte(HiWord(pIpe^.Address)));
if error=0 then
msg:= 'Reply from '+ IPReply
+ ' bytes='+
IntToStr(sizeof(pingBuffer)) +
' time='
+
IntToStr(pIpe.RTTime)+' ms'
else msg:= 'Reqested Timed out.';
if (LoByte(LoWord(pIpe^.Status)))=250 then
msg:= 'Destination host unreachable.' ;
end;
if pos(msg3,msg)<>0 then msg:='Destination host unreachable.' ;{сравнение IP хоста с IP отвечающей железяки}
msg:= datetimetostr(now)+' '+msg;
Synchronize(UpdateGrid);
IcmpCloseHandle(hIP);
WSACleanup();
FreeMem(pIpe);
end;
Игорь Шевченко (2010-04-06 19:28:00) [11]код потока в студию