Форум: "Начинающим";
Текущий архив: 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 //âñå ïîäñåòè
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
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