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

Вниз

Потоки и 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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.51 MB
Время: 0.046 c
15-1231749928
b@v
2009-01-12 11:45
2009.03.15
Поиск по базе


15-1230182983
novai
2008-12-25 08:29
2009.03.15
как очистить таблицу от записей в access?


4-1206457103
Informer
2008-03-25 17:58
2009.03.15
Кнопка закрытия формы


4-1206607413
kolj
2008-03-27 11:43
2009.03.15
Tapi -> LineGetId


6-1200389418
chemelin
2008-01-15 12:30
2009.03.15
Помогите с winsocket в WinAPI





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский