【发布时间】:2012-10-12 11:56:46
【问题描述】:
我有一个有 60 台计算机/设备的房间(40 台计算机和 20 台基于 Windows CE 的示波器),我想知道使用 ping 的每个人都还活着。首先,我编写了一个标准 ping(参见此处 Delphi Indy Ping Error 10040),它现在运行良好,但在大多数计算机离线时需要很长时间。
所以我想做的是写一个多线程 Ping,但我很挣扎。我在互联网上只看到很少的例子,没有一个符合我的需求,这就是我尝试自己写的原因。
我使用 XE2 和 Indy 10,表单仅由备忘录和按钮组成。
unit Main;
interface
uses
Winapi.Windows, System.SysUtils, System.Classes, Vcl.Forms,
IdIcmpClient, IdGlobal, Vcl.StdCtrls, Vcl.Controls;
type
TMainForm = class(TForm)
Memo1: TMemo;
ButtonStartPing: TButton;
procedure ButtonStartPingClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type
TMyPingThread = class(TThread)
private
fIndex : integer;
fIdIcmpClient: TIdIcmpClient;
procedure doOnPingReply;
protected
procedure Execute; override;
public
constructor Create(index: integer);
end;
var
MainForm: TMainForm;
ThreadCOunt : integer;
implementation
{$R *.dfm}
constructor TMyPingThread.Create(index: integer);
begin
inherited Create(false);
fIndex := index;
fIdIcmpClient := TIdIcmpClient.Create(nil);
fIdIcmpClient.ReceiveTimeout := 200;
fIdIcmpClient.PacketSize := 24;
fIdIcmpClient.Protocol := 1;
fIdIcmpClient.IPVersion := Id_IPv4;
//first computer is at adresse 211
fIdIcmpClient.Host := '128.178.26.'+inttostr(211+index-1);
self.FreeOnTerminate := true;
end;
procedure TMyPingThread.doOnPingReply;
begin
MainForm.Memo1.lines.add(inttostr(findex)+' '+fIdIcmpClient.ReplyStatus.Msg);
dec(ThreadCount);
if ThreadCount = 0 then
MainForm.Memo1.lines.add('--- End ---');
end;
procedure TMyPingThread.Execute;
begin
inherited;
try
fIdIcmpClient.Ping('',findex);
except
end;
while not Terminated do
begin
if fIdIcmpClient.ReplyStatus.SequenceId = findex then Terminate;
end;
Synchronize(doOnPingReply);
fIdIcmpClient.Free;
end;
procedure TMainForm.ButtonStartPingClick(Sender: TObject);
var
i: integer;
myPing : TMyPingThread;
begin
Memo1.Lines.Clear;
ThreadCount := 0;
for i := 1 to 40 do
begin
inc(ThreadCount);
myPing := TMyPingThread.Create(i);
//sleep(10);
end;
end;
end.
我的问题是,当我取消注释“sleep(10)”时,它“似乎”可以工作,而没有它“似乎”就无法工作。这肯定意味着我在编写的线程中遗漏了一点。
换句话说。当 Sleep(10) 在代码中时。每次我单击按钮检查连接时,结果都是正确的。
没有睡眠(10),它“大部分”时间都在工作,但有时结果是错误的到正确的线程。
欢迎任何意见或帮助。
----- 编辑/重要 -----
作为对这个问题的一般跟进,@Darian Miller 启动了一个 Google Code project here https://code.google.com/p/delphi-stackoverflow/ 这是一个工作基础。我将他的答案标记为“已接受的答案”,但用户应该参考这个开源项目(所有功劳归他所有),因为它肯定会在未来扩展和更新。
【问题讨论】:
-
我会重复我的建议 - 放弃股票 TThread 并使用 AsyncCalls 或 OmniThreads。你的线程实现对我来说似乎大多是单线程的!
-
'继承的 Create(false);' - 在 ctor 完成其字段的初始化之前,这可能不会运行线程吗?
-
..而且,ICMP ping 没有套接字上下文等。我不相信发送 ping 的线程会收到 gnip,因此 findex 将不匹配:'ReplyStatus.SequenceId = findex' 通常是错误的。 '好像 ping 回复没有分配给正确的线程' - 是的。
-
@Martin 我不知道 idICMP 的实现是什么,但sample of using Windows API 建议最明显的实现不会使用线程和消息队列,而只使用回调。坦率地说,我认为如果 topicstarter 在这里放弃 Indy 并直接使用 API - 他可以轻松地通过单线程(或至少可能是双线程)应用程序实现并行 ping,这将不那么繁重,而且更简单。我不知道 Windows 会通过哪种方法以及在哪个线程/上下文中调用该回调...
-
+1 @Martin。非常有趣的一点。
标签: multithreading delphi ping indy tthread