Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.03.15;
Скачать: CL | DM;

Вниз

Потоки и Indy   Найти похожие ветки 

 
charoey_mag   (2009-01-21 09:19) [0]

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


 TMyThread = class(TThread)
   FIP:string;
   FICMP:TIdIcmpClient;
   FNIP:string;
   FFinish:boolean;
   procedure ICMPReply(ASender: TComponent; const AReplyStatus: TReplyStatus);
   function GetNameFromIP(const IP: String): String;
 protected
   property Finish: boolean read FFinish;
   procedure Execute; override;
 public
   constructor Create(ip:string);
 end;

type
 ta  = array[0..2] of string;

var
 Form1: TForm1;
 nip:string;
 din:array[1..254] of ta;
 CriticalSection: TRTLCriticalSection;

implementation

{$R *.dfm}

constructor TMyThread.Create(ip:string);
begin
 FIP:=ip;
 FICMP:=TIdIcmpClient.Create(Form1);
 FICMP.Host:=ip;
 FICMP.ReceiveTimeout:=1500;
 FICMP.OnReply:=ICMPReply;
 FNIP:="";
 FFinish:=false;
 FreeOnTerminate := True;
 inherited Create(False);
end;

function TMyThread.GetNameFromIP(const IP: String): String;
var
 WSA: TWSAData;
 Host: PHostEnt;
 Addr: Integer;
begin
Result := "";
if WSAStartup($101, WSA) <> 0 then
 Exit;
try
  Addr := inet_addr(PChar(IP));
  if Addr = INADDR_NONE then
  begin
    WSACleanup;
    Exit;
  end;
  Host := gethostbyaddr(@Addr, SizeOf(Addr), PF_INET);
  if Assigned(Host) then
    Result := Host.h_name;
finally
  WSACleanup;
end;
end;

procedure TMyThread.ICMPReply(ASender: TComponent;
 const AReplyStatus: TReplyStatus);
var
 sTime: string;
begin
if (AReplyStatus.MsRoundTripTime = 0) then
   sTime := "<1"
 else
   sTime := "=";
 if AReplyStatus.BytesReceived<>0 then
   FNIP:=GetNameFromIP(AReplyStatus.FromIpAddress)
 else
   FNIP:="-";
end;

procedure TMyThread.Execute;
var i:integer;
begin
//EnterCriticalSection(CriticalSection);
FICMP.Ping;
i:=length(FIP);
while FIP[i]<>"." do
 dec(i);
i:=StrToInt(copy(FIP,i+1,length(FIP)-i+1));
din[i][2]:=FNIP;
FFinish:=true;
//LeaveCriticalSection(CriticalSection);
end;


Код вызова потока:

procedure TForm1.Button5Click(Sender: TObject);
var i,j,k,l,m:integer;
   ipn,ip:string;
   item:TListItem;
   mt:array[1..10] of TMyThread;
begin
InitializeCriticalSection(CriticalSection);
ListView1.Clear;
for i:=0 to ListBox2.Count-1 do //все подсети
 begin
 ipn:=Copy(ListBox2.Items[i],1,length(ListBox2.Items[i])-1);
 FillChar(din,SizeOf(din),0);
 FillChar(mt,SizeOf(mt),0);
 for j:=1 to 254 do  //все адреса в подсети
   begin
   ip:=ipn+IntToStr(j);
   din[j][0]:="";
   din[j][1]:=ip;
   m:=0;
   repeat
   Application.ProcessMessages;
   l:=0;
   for k:=1 to 10 do
     if mt[k]<>nil then
       begin
       if mt[k].Finish then
         mt[k]:=nil
       else
         inc(l);
       end
     else
       m:=k;
   until l<10;
   mt[m]:=TMyThread.Create(ip);
   ProgressBar1.Position:=round(j*100/254);
   end;
 l:=0;
 repeat
   Application.ProcessMessages;
   for k:=1 to 100 do
     if mt[k]<>nil then
       inc(l);
 until l>0;
 for j:=1 to 254 do
   begin
   Application.ProcessMessages;
   item:=ListView1.Items.add;
   item.Caption:=din[j][0];
   item.SubItems.Add(din[j][1]);
   item.SubItems.Add(din[j][2]);
   end;
 end;
ProgressBar1.Position:=0;
DeleteCriticalSection(CriticalSection);
Memo1.Lines.Assign(l2);
end;


Работает быстро, но результаты выглядят так:

10.214.106.1 F302
10.214.106.2 F302
10.214.106.3 F304
10.214.106.4 F304
10.214.106.5 F306
10.214.106.6 F306
10.214.106.7 F308
10.214.106.8 F308
10.214.106.9 F314
10.214.106.10 F314
10.214.106.11 F314
10.214.106.12 F314
Т.е получается если компьютер в сети то он бысто отвечает на запрос, а остальным потокам которые ждут таймаута, присваивается имя ответившего компьютера

Если Execute поместить в
EnterCriticalSection(CriticalSection);
LeaveCriticalSection(CriticalSection);
То работает медленно но результат правильный:
10.214.106.1 -
10.214.106.2 F302
10.214.106.3 -
10.214.106.4 F304
10.214.106.5 -
10.214.106.6 F306
10.214.106.7 -
10.214.106.8 F308
10.214.106.9 -
10.214.106.10 -
10.214.106.11 -
10.214.106.12 -
10.214.106.13 -
10.214.106.14 F314
10.214.106.15 F315

Подскажите почему потоки пересекаются? Ведь у каждого же свои собственные переменные


 
Медвежонок Пятачок ©   (2009-01-21 11:28) [1]

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


 
Медвежонок Пятачок ©   (2009-01-21 11:39) [2]

Плюс убрать явную дурь с использованием глобальных переменных несколькими потоками


 
Сергей М. ©   (2009-01-21 12:30) [3]


> у тех кто ответит спрашивается имя


Те, кто не ответил (по разным причинам), тоже вправе и могут иметь имя.


 
charoey_mag   (2009-01-21 12:38) [4]


> К делу не относится, но зачем в нитке использовать событийную
> модель?пинг синхронный, после него доступен статус.накой
> еще потребовалось лепить обработчик?

Убрал ничего не изменилось

> Плюс убрать явную дурь с использованием глобальных переменных
> несколькими потоками

Да но каждый поток записывает только в одну, уже существующую ячейку массива, с этим то что не так?


 
Медвежонок Пятачок ©   (2009-01-21 12:40) [5]

с этим то что не так?

то не так, что все эти глобальные переменные нафик не нужны.


 
charoey_mag   (2009-01-21 13:04) [6]

Изменил, ничего не изменилось


 
Медвежонок Пятачок ©   (2009-01-21 14:11) [7]

посмотри в 17-й строке измененного исходника.
ошибка там.


 
charoey_mag   (2009-01-21 14:25) [8]

Вот исправленный код:

 TMyThread = class(TThread)
   FIP:string;
   FICMP:TIdIcmpClient;
   FNIP:string;
   FFinish:boolean;
   function GetNameFromIP(const IP: String): String;
 protected
   property IP: string read FIP;
   property NIP: string read FNIP;
   property Finish: boolean read FFinish;
   procedure Execute; override;
 public
   constructor Create(ip:string);
   destructor Destroy; override;
 end;

type
 ta  = array[0..2] of string;

var
 Form1: TForm1;
 nip:string;
 din:array[1..254] of ta;
 CriticalSection: TRTLCriticalSection;

implementation

{$R *.dfm}

constructor TMyThread.Create(ip:string);
var s:string;
begin
 FIP:=ip;
 FICMP:=TIdIcmpClient.Create(Form1);
 FICMP.Host:=ip;
 s:=ip;
 while pos(".",s)<>0 do
   Delete(s,pos(".",s),1);
 FICMP.Name:="ICMP"+s;
 FICMP.ReceiveTimeout:=2500;
 FNIP:="";
 FFinish:=false;
 FreeOnTerminate :=False;// True;
 inherited Create(False);
end;

destructor TMyThread.Destroy;
begin
FICMP.Destroy;
inherited Destroy;
end;

function TMyThread.GetNameFromIP(const IP: String): String;
var
 WSA: TWSAData;
 Host: PHostEnt;
 Addr: Integer;
begin

Result := "";
if WSAStartup($101, WSA) <> 0 then
 Exit;
try
  Addr := inet_addr(PChar(IP));
  if Addr = INADDR_NONE then
  begin
    WSACleanup;
    Exit;
  end;
  Host := gethostbyaddr(@Addr, SizeOf(Addr), PF_INET);
  if Assigned(Host) then
    Result := Host.h_name;
finally
  WSACleanup;
end;
end;

procedure TMyThread.Execute;
begin
///EnterCriticalSection(CriticalSection);
FICMP.Ping;
if FICMP.ReplyStatus.BytesReceived<>0 then
   FNIP:=GetNameFromIP(FICMP.ReplyStatus.FromIpAddress)
 else
   FNIP:="-";
FFinish:=true;
//LeaveCriticalSection(CriticalSection);
end;


Процедура вызова:


procedure TForm1.Button5Click(Sender: TObject);
var i,j,k,l,m,n:integer;
   ipn,ip:string;
   item:TListItem;
   mt:array[1..10] of TMyThread;
begin
InitializeCriticalSection(CriticalSection);
ListView1.Clear;
for i:=0 to ListBox2.Count-1 do //&#226;&#241;&#229; &#239;&#238;&#228;&#241;&#229;&#242;&#232;
 begin
 ipn:=Copy(ListBox2.Items[i],1,length(ListBox2.Items[i])-1);
 FillChar(din,SizeOf(din),0);
 FillChar(mt,SizeOf(mt),0);
 for j:=1 to 254 do  //&#226;&#241;&#229; &#224;&#228;&#240;&#229;&#241;&#224; &#239;&#238;&#228;&#241;&#229;&#242;&#232;
   begin
   ip:=ipn+IntToStr(j);
   din[j][0]:="";
   din[j][1]:=ip;
   m:=0;
   repeat
   Application.ProcessMessages;
   l:=0;
   for k:=1 to 10 do
     if mt[k]<>nil then
       begin
       if mt[k].Finish then
         begin
         n:=length(mt[k].IP);
         while mt[k].IP[n]<>"." do
           dec(n);
         n:=StrToInt(copy(mt[k].IP,n+1,length(mt[k].IP)-n+1));
         din[n][2]:=mt[k].NIP;
         mt[k].Free;
         mt[k]:=nil;
         end
       else
         inc(l);
       end
     else
       m:=k;
   until l<10;
   mt[m]:=TMyThread.Create(ip);
   ProgressBar1.Position:=round(j*100/254);
   end;
 l:=0;
 repeat
   Application.ProcessMessages;
   for k:=1 to 100 do
     if mt[k]<>nil then
       inc(l);
 until l>0;
 for j:=1 to 254 do
   begin
   Application.ProcessMessages;
   item:=ListView1.Items.add;
   item.Caption:=din[j][0];
   item.SubItems.Add(din[j][1]);
   item.SubItems.Add(din[j][2]);
   end;
 end;
ProgressBar1.Position:=0;
DeleteCriticalSection(CriticalSection);
end;


 
charoey_mag   (2009-01-21 14:25) [9]

Удалено модератором


 
Медвежонок Пятачок ©   (2009-01-21 14:41) [10]

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

не так все это пишется.
идет итерация по проверяемым элементам.
для каждой создается поток.
потоку при создании передается исчерпывающая инфа о параметрах его работы. Чтобы изнутри execute он не лез никудаю Ни на формы ни в массивы глобальные.
Получив результаты своей работы, поток информирует пользовательский интерфейс о них. И снова без всяких чудовищных модификаций глобальный структур.

Если написать так, то кода твоего поубавится раза в четыре.
И сразу будет наглядно видно что и где косячит.

А в таком спагетти коде разбираться будет только извращенец какой-нибудь


 
charoey_mag   (2009-01-21 14:58) [11]

Я извиняюсь за дубликат сообщения, я не специально)))

FICMP:=TIdIcmpClient.Create(Form1);
Используется только потому что Create требует TComponent

Внутри класса лобальных переменных больше нет.

В вызове потоков тоже вроде ничего страшного

for //пройтись по всем подсетям, тока тестю, подсеть одна
 for j:=1 to 254 //все адреса подсети
   repeat
     for k:=1 to 10 //проверка кол-ва свободных ячеек в массиве потоков
   until   //ждать пока не освободиться
   //создать новый поток в найденной свободной ячейке

В поток передается только ip
Create(ip);
Возвращается:
property IP
property NIP
property Finish

Вобщем вроде ничего сложного...


 
Медвежонок Пятачок ©   (2009-01-21 15:01) [12]

твой главный алгоритм, создающий потоки, и рассовывающий их по массиву, затем еще и шарищийся по массивам в поисках результатов работы - вот источник хаоса


 
charoey_mag   (2009-01-22 10:49) [13]


> твой главный алгоритм, создающий потоки, и рассовывающий
> их по массиву, затем еще и шарищийся по массивам в поисках
> результатов работы - вот источник хаоса

С потоками все таки все нормально было, убрал котпонент TIdIcmpClient и вставил код использующий ICMP API, и сразу все стало нормально работать. Видимо Indy не совметимо с многопоточностью, или только этот компонент.


 
Сергей М. ©   (2009-01-22 11:05) [14]


> charoey_mag


Совместим или несовместим - это отдельная песня.
Тебя ждет совсем другая засада, и ты попадешь в нее, когда будешь работать с подсетями, например, класса A и B - ты не сможешь создать столько одновременно работающих пингующих потоков.


 
charoey_mag   (2009-01-22 11:34) [15]


> Тебя ждет совсем другая засада, и ты попадешь в нее, когда
> будешь работать с подсетями, например, класса A и B - ты
> не сможешь создать столько одновременно работающих пингующих
> потоков.


Ну для этого и есть
mt:array[1..10] of TMyThread;
одновремеено работают максимум 10 потоков. С этим я тоже хотел бы поэкспериментировать, а сколько максимально/оптимально использовать потоков?


 
Сергей М. ©   (2009-01-22 11:57) [16]


> сколько максимально/оптимально использовать потоков?


"Максимально" - зависит от аппетитов на вирт.память каждого потока. TThread по дифолту съедает как минимум 1мб в стеке. А у тебя всего-то в теории максимум 2гб в распоряжении.

"Оптимально" - в Инди есть компонент, реализующий тред-пул и его менеджмент.



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

Текущий архив: 2009.03.15;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.018 c
6-1200679020
ad_Wolf
2008-01-18 20:57
2009.03.15
Вопрос по Indy


2-1232648122
cruiser
2009-01-22 21:15
2009.03.15
Ожидание отработки операций внутри отдельного потока


2-1232625697
fat.hamster
2009-01-22 15:01
2009.03.15
Правильный способ обработки ошибок в OnCreate?


2-1232749601
donduras
2009-01-24 01:26
2009.03.15
Перетаскивание динамически созданных image


2-1232630826
EastGod
2009-01-22 16:27
2009.03.15
Получить общую громкость