PDA

View Full Version : سوال: مشکل در ساخت Thread



Mask
یک شنبه 18 دی 1390, 13:49 عصر
با سلام.
نمونه زیر رو ملاحظه بفرمایید.
مشکلم اینه اگه تا هنوز کار حلقه به اتمام نرسیده برنامه رو ببندم AV میده برنامه.
چطوری باید این مشکل رو رفع کرد.

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdBaseComponent, IdComponent, IdIPWatch, StdCtrls, IdRawBase,
IdRawClient, IdIcmpClient, Spin;

type
TPingThread=class(TThread)
protected
procedure execute; override;
procedure ShowIn;
end;

type
TForm1 = class(TForm)
IdIcmpClient1: TIdIcmpClient;
Edit1: TEdit;
Memo1: TMemo;
Button1: TButton;
SpinEdit1: TSpinEdit;
SpinEdit2: TSpinEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
procedure IdIcmpClient1Reply(ASender: TComponent;
const AReplyStatus: TReplyStatus);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
i: byte;
implementation

{$R *.dfm}

procedure TForm1.IdIcmpClient1Reply(ASender: TComponent;
const AReplyStatus: TReplyStatus);
begin
Memo1.lines.Add(inttostr(i)+'- host '+AReplyStatus.FromIpAddress+' sent '+inttostr(AReplyStatus.BytesReceived)+' bytes date in '+IntToStr(AReplyStatus.MsRoundTripTime)+' ms.');
end;

procedure TForm1.Button1Click(Sender: TObject);
var ping:TPingThread;
begin
ping:=TPingThread.Create(false);
ping.FreeOnTerminate:=true;
ping.Resume;
end;

{ TPingThread }

procedure TPingThread.execute;
begin
inherited;
ShowIn;
end;

procedure TPingThread.ShowIn;
begin
form1.IdIcmpClient1.ReceiveTimeout:=form1.SpinEdit 2.Value;
form1.IdIcmpClient1.Host:=form1.edit1.Text;
for i:=1 to form1.SpinEdit1.Value do
form1.IdIcmpClient1.Ping('',0);
form1.memo1.Lines.Add('-----------------------------------------------------------------------------------------');
end;

end.

BORHAN TEC
یک شنبه 18 دی 1390, 14:21 عصر
برنامه رو به شکل زیر بنویسید. برنامه رو هم ضمیمه نمی کنم که خودتون هم مثل من زحمت ساخت یک پروژه رو بکشید! :لبخند: :چشمک:
unit Unit1;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdBaseComponent,
IdComponent, IdRawBase, IdRawClient, IdIcmpClient, Vcl.Samples.Spin;

type
TPingThread = class(TThread)
protected
procedure execute; override;
procedure ShowIn;
end;

type
TForm1 = class(TForm)
IdIcmpClient1: TIdIcmpClient;
Memo1: TMemo;
Button1: TButton;
SpinEdit1: TSpinEdit;
SpinEdit2: TSpinEdit;
Edit1: TEdit;
procedure IdIcmpClient1Reply(ASender: TComponent;
const AReplyStatus: TReplyStatus);
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

// Look at This:
i: Integer;
CloseFlag: Boolean;
/// //////////////

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
ping: TPingThread;
begin
ping := TPingThread.Create(false);
ping.FreeOnTerminate := true;
ping.Resume;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
// Look at This:
CloseFlag := true;
/// //////////////
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
// Look at This:
CloseFlag := false;
/// //////////////
end;

procedure TForm1.IdIcmpClient1Reply(ASender: TComponent;
const AReplyStatus: TReplyStatus);
begin
Memo1.lines.Add(inttostr(i) + '- host ' + AReplyStatus.FromIpAddress +
' sent ' + inttostr(AReplyStatus.BytesReceived) + ' bytes date in ' +
inttostr(AReplyStatus.MsRoundTripTime) + ' ms.');
end;

{ TPingThread }

procedure TPingThread.execute;
begin
inherited;

// Look at this:
Synchronize(ShowIn);
/// /////////////////
end;

procedure TPingThread.ShowIn;
begin
Form1.IdIcmpClient1.ReceiveTimeout := Form1.SpinEdit2.Value;
Form1.IdIcmpClient1.Host := Form1.Edit1.Text;
for i := 1 to Form1.SpinEdit1.Value do
begin
// Look at this:
if CloseFlag then
begin
break;
end;
Application.ProcessMessages;
/// /////////////////
Form1.IdIcmpClient1.ping('', 0);
end;
Form1.Memo1.lines.Add
('-----------------------------------------------------------------------------------------');
end;

end.

Mask
یک شنبه 18 دی 1390, 14:54 عصر
ممنون.
اما چرا وقتی از

Synchronize(ShowIn);
استفاده میکنید و کد

Application.ProcessMessages;
رو بر میداریم. برنامه با اینکه داره عملیات پینگ رو تو یه ترد دیگه اجرا میشه بازم برنامه قفله.؟ در ضمن نمیخام از Application.ProcessMessages استفاده کنم. چون اینجوری دیگه نیاز نیست عملیات پینگ رو در یه تر دیگه پیاده سازی کنم. و تو همون ترد اصلی با Application.ProcessMessages فرم رو از حالت قفل در میارم.
و یه موضوع دیگه اینکه متد Synchronize مگه برای همزمان سازی ترد ها با ترد اصلی نیست. پس چرا وقتی از این متد استفاده میشه فرم قفل میشه اما مثل کد اول من وقتی از این متد استفاده نمیشه برنامه قفل نمیشه و روند اجرایی برنامه بدون مشکل انجام میشه؟

Felony
یک شنبه 18 دی 1390, 15:09 عصر
P
ممنون.
اما چرا وقتی از

Synchronize(ShowIn);
استفاده میکنید و کد

Application.ProcessMessages;
رو بر میداریم. برنامه با اینکه داره عملیات پینگ رو تو یه ترد دیگه اجرا میشه بازم برنامه قفله.؟ در ضمن نمیخام از Application.ProcessMessages استفاده کنم. چون اینجوری دیگه نیاز نیست عملیات پینگ رو در یه تر دیگه پیاده سازی کنم. و تو همون ترد اصلی با Application.ProcessMessages فرم رو از حالت قفل در میارم.
و یه موضوع دیگه اینکه متد Synchronize مگه برای همزمان سازی ترد ها با ترد اصلی نیست. پس چرا وقتی از این متد استفاده میشه فرم قفل میشه اما مثل کد اول من وقتی از این متد استفاده نمیشه برنامه قفل نمیشه و روند اجرایی برنامه بدون مشکل انجام میشه؟
متد Synchronize عمليات مورد نظر شما رو در Context ترد اصلي برنامه انجام ميده ، بنابراين وقتي از متد Synchronize استفاده ميكنيد Main Thread كه وظيفه به روزرساني رابط كاربري رو داره كار عادي خودش رو در اولين فرصت كنار ميزاره و به اجراي كد شما رسيدكي ميكنه ، بنابراين كدي كه نوشتيد با نوشتن مستقيم اون كد تو خود برنامه تفاوتي نداره جون در هر صورت توسط Main Thread اجرا ميشه !

ديروز هم در اين مورد بهتون توضيح دادم كه بهتره از Message ها استفاده كني .

Mask
یک شنبه 18 دی 1390, 15:56 عصر
ممنون.
این کد رو ببینید.
این شی رو به صورت رانتایم میسازم.
اما مشکل داره.

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdBaseComponent, IdComponent, IdIPWatch, StdCtrls, IdRawBase,
IdRawClient, IdIcmpClient, Spin;

type
TPingThread=class(TThread)
public
procedure MyReply(ASender: TComponent;const AReplyStatus: TReplyStatus);
protected
procedure execute; override;
end;

type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
Procedure WndProc(var Message: TMessage); Override;
{ Public declarations }
end;

var
Form1: TForm1;
i:byte;
WM_Msg_TH: DWord;
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var ping:TPingThread;
begin
for i := 1 to 10 do
begin
ping:=TPingThread.Create(false);
ping.FreeOnTerminate:=true;
ping.Resume;
end;
end;

{ TPingThread }

procedure TPingThread.execute;
var
IdIcmpClient:TIdIcmpClient;
begin
inherited;
IdIcmpClient:= TIdIcmpClient.Create();
try
with IdIcmpClient do
begin
ReceiveTimeout := 1000;
Protocol := 1;
ProtocolIPv6 := 0;
PacketSize := 1024;
Host:='4.2.2.4';
OnReply:=MyReply;
end;
IdIcmpClient.Ping('',0);
finally
IdIcmpClient.Free;
end;
end;

procedure TPingThread.MyReply(ASender: TComponent;
const AReplyStatus: TReplyStatus);
var str:string;
begin
str:=(inttostr(i)+'- host '+AReplyStatus.FromIpAddress+' sent '+inttostr(AReplyStatus.BytesReceived)+' bytes date in '+IntToStr(AReplyStatus.MsRoundTripTime)+' ms.');
SendMessage(Form1.Handle, WM_Msg_TH, Integer(Str), 0);
end;

procedure TForm1.WndProc(var Message: TMessage);
var Id:string;
begin
if Message.Msg= WM_Msg_TH then
begin
ID:=String(Message.WParam);
Memo1.Lines.Add(Id);
end;

inherited;
end;

end.

Felony
یک شنبه 18 دی 1390, 16:02 عصر
مشكل داره يعني جي ؟! مشكلتون رو مطرح كنيد ...

Mask
یک شنبه 18 دی 1390, 16:05 عصر
اولا که، اگه حلقه رو بزارم رو، 100 ،برنامه گیر میکنه و یهویی 100 تا خط میاد تو ممو و همشون هم شکل همند.
دوم اینکه تو برنامه اولیه که به صورت RunTime نیست و خود کامپوننت در ترد اصلی کار میکنه، دقیقا وقتی برنامه 4.2.2.4 رو پینک میکنه ، اعداد با هم فرق دارند ودونه دونه به ممو اضافه میشوند.

Mahmood_M
دوشنبه 19 دی 1390, 02:02 صبح
نیازی به استفاده از Message ها نیست ، با SendMessage چی رو ارسال میکنید ؟ ، مقداری که در WParam ارسال میشه ، آدرس فضای متغیر Str هست نه مقدار درونش !
سعی کنید تعداد Thread ها رو به حداقل برسونید که مدیریتشون راحت تر بشه ، برای نمایش مقدار در Memo هم کافیه که فقط برای نوشتن متن در Memo از Synchronize استفاده کنید ، یک نمونه ضمیمه کردم

موفق باشید ...

Mask
دوشنبه 19 دی 1390, 08:43 صبح
مقداری که در WParam ارسال میشه ، آدرس فضای متغیر Str هست
ممنون .داداش
فقط اینکه وقتی ما از دستور

String(Message.WParam);
استفاده میکنیم. مگه منظور این نیست که مقدار درونی این فضا رو نشون بده نه آدرسش رو؟
و یه مورد دیگه، که خیلی فکرمو مشغول کرده اینه که : نمونه برنامه شما یا نمونه های دیگه ای که با ترد کار میکنند رو وقتی با ProcessExplorer مانیتور میکنم .تو سربرگ ترد ،فقط اسم ترد ها میاد و در صورتی که برنامه های من تو سر برگ ترد چیزهای دیگه ای هم هست (عکس زیر ).اگه محبت کنید بفرمایید :اینا قضیشون چیه.آیا مشکل در پیاده سازیه. یا مشکلی نداره.؟البته برانامه های دیگه رو هم که دیدم.اونایی که رو سیستم نصبه مثله آنتی ویروس، اونا هم یه همچین تردهایی داشتند.
و یه موضوع دیگه اینکه اگه بخواهیم برنامه با یه حلقه مثلا 1000 تایی فقط یه آی پی رو پینگ کنیم. چطوری میشه.
در ضمن کدی که در بالا با SendMesage نوشتم هم. بهم کار میده.اما وقتی میزارمش تو حلقه مشکل پیدا میکنه.
ممنون.