PDA

View Full Version : مشكل در پياده سازي و بكاري گيري رويه هاي تعريف شده در كلاس ها



ali_mohamadi8928
دوشنبه 13 آبان 1387, 22:08 عصر
سلام خدمت همه ي دوستان عزيز .

يك راهنمايي از دوستان ميخوام به خصوص از اقاي كشاورز چون تا اونجايي كه ديدم بيشتر ايشون به اين مدل سوالات جواب ميده .

من يك كامپوننت براي مثال طراحي كردم تا بتونم منظورم رو برسونم .

اين كاپوننت از كلاس TComponent مشتق ميشه .

در بخش خصوصي كلاس اين كامپوننت يك متغير عددي تعريف كردم كه به عنوان يك شمارنده است .

و يك رويه در قسمت عمومي تعريف كردم كه عمل اظافه كردن مقدار به شمارنده رو با گام يك انجام ميده .

بعد اومدم يك كلاس از نوع TThread ساختم كه وظيفه ي اجرا كردن رويه اي كه عمل اظافه كردن مقدار به شمارنده رو انجام ميده رو بر عهده داره .

بعد من رويه ي Create كامپوننتم رو بازنويسي كردم و در اون TThread رو هم Create كردم و با توجه به مابحث كار با Thread ها رويه ي Execute اون اجرا ميشه و بعد از مقدار دادن بعضي از متدهاي خودش كار صدا زدن يك رويه ي ديگه كه وظيفه ي صدا زدن پشت سر هم رويه ي شمارنده را بر عهده دارد انجام ميدهد .

خوب حالا همه ي اين مراحل درست انجام ميشه به جز يك جاش . رويه اي كه در Execute صدا زده ميشه كه بايد رويه ي شمارنده از كلاس كامپوننت رو صدا بزنه نميدونم چرا هر كاري ميكنم خطا ميگيره و نميتونه اون رو صدا بزنه . اين در حالي هست كه رويه ي شمارنده در بخش عمومي تعريف شده ولي نميدونم چرا نميشه .

من براي اطمينان كد كاملش رو ميزارم و جايي كه مشكل داره رو هم با رنگ قرمز مشخص ميكنم تا خودتون ببينيد
.
چيكار بايد بكنم تا به صورت استاندار اين مشكل حل بشه .

ضميمه : اين كدها فقط جهت اين هست كه بتونم منظورم رو برسونم . در واقع اين مشكل در كامپوننتي كه دارم مينويسم برام پيش اومده كه از همين حالت استفاده ميخوام بكنم تا بتونم يه رويه رو با يك thread اجرا كنم تا برنامه دچار مشكل نشه . چون عملياتي كه توي اون رويه انجام ميگيره خيلي سنگين هست براي همين نميخوام از تايمر و .. استفاده كنم . وگرنه اگه از تايمر استفاده كنم مشكل حل ميشه ولي نتيجه ي مطلوبي توي سرعت بهم نميده .

به قسمتي در كدها كه قرمز كردم توجه كنيد . چون فقط همونجا مشكل داره :ناراحت:


unit UseThread;
interface
uses
SysUtils, Classes;
type
TUseThread = class(TComponent)
private
fnum: Integer;
protected
{ Protected declarations }
public
constructor Create(AnOwner: TComponent); override;
procedure test;
published
{ Published declarations }
end;
type
TTestThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
public
end;
procedure Register;
implementation
procedure TUseThread.test;
begin
fnum := fnum + 1;
end;
procedure RunProcs;
var
wh: Boolean;
begin
wh := TRUE;
while wh do begin
TUseThread.test;
sleep(1000);
end;
end;
procedure TTestThread.Execute;
begin
{ Place thread code here }
FreeOnTerminate := TRUE;
Priority := tpHigher;
RunProcs;
DoTerminate;
end;
constructor TUseThread.Create(AnOwner: TComponent);
begin
inherited;
fnum := 0;
with TTestThread.Create(TRUE) do begin
Suspended := false;
end;
end;
procedure Register;
begin
RegisterComponents('TestComp', [TUseThread]);
end;
end.

ghabil
دوشنبه 13 آبان 1387, 23:05 عصر
TUserThread.Test یعنی چی ؟ مگه Test یک Class procedure که با اسم کلاسش صداش میزنی؟! مگه مثلا هیچ وقت مینویسی TButton.Click? همیشه یک Instance از کلاس میسازی و بعد روالهای اون آبجکت رو صدا میزنی ، اینجا هم باید یک آبجکت از نوع TUserThread بسازی (Create بکنی) بعد اون رو له RunProcess پاس بکنی :


RunProcess(AThread: TUserThread);
.....
AThread.Test;
....

ali_mohamadi8928
دوشنبه 13 آبان 1387, 23:30 عصر
سلام اقاي كوشا .

اصلا كلاسي با نام


TUserThread

در اين كدها وجود نداره !!!!

خوب مگه در هنگام Create شدن كلاس TUseThread به صورت اتوماتيك يك نمونه ازش ايجاد نميشه ؟ خوب من ميخوام رويه ي مربوط به همون رو اجرا كنم نه اينكه يك نمونه ي جديد خودم بسازم و رويش رو صدا كنم . در ضمن كلاس TUseThread از نوع TComponent هست و اون Thread فقط نقشش اينه كه مثل يك تايمر بايد يك رويه از كلاس TUseThread رو در يك باجه ي زماني خاص اجرا كنه .

ولي من نميدونم چه جوري بايد به اون رويه از نمونه ي اي كه اتوماتيك ايجاد ميشه و در بخش عمومي تعريف شده توسط يك رويه ي ديگه دسترسي داشته باشم .

اگه كد رو خوب مطالعه كنيد منظورم رو كاملا ميفهميد .

با تشكر

مهران موسوی
دوشنبه 13 آبان 1387, 23:53 عصر
مشكلت رو حل كردم .....

كدت رو ويرايش كردم ... به كد ويرايش شده توجه كن ... اگه دليلش هم خواستي بدوني اعلام كن تا برات توضيح بدم ....



unit UseThread;

interface

uses
SysUtils, Classes;

type
TUseThread = class(TComponent)
private
fnum: Integer;
protected
{ Protected declarations }
public
constructor Create(AnOwner: TComponent); override;
procedure test;
published
{ Published declarations }
end;

type
TTestThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
public
end;

procedure Register;

var
UseThreadPoint:TUseThread;

implementation

procedure TUseThread.test;
begin
fnum := fnum + 1;
end;

procedure RunProcs;
var
wh: Boolean;
begin

wh := TRUE;

while wh do begin
UseThreadPoint.test;
sleep(1000);
end;

end;

procedure TTestThread.Execute;
begin
{ Place thread code here }
FreeOnTerminate := TRUE;
Priority := tpHigher;
RunProcs;
DoTerminate;
end;

constructor TUseThread.Create(AnOwner: TComponent);
begin
inherited;

UseThreadPoint:=Self;

fnum := 0;

with TTestThread.Create(TRUE) do begin
Suspended := false;
end;

end;

procedure Register;
begin
RegisterComponents('TestComp', [TUseThread]);
end;

end.

ghabil
دوشنبه 13 آبان 1387, 23:55 عصر
مگه RunProcess شما توی کلاس TUSEThread هست که به Instance خودش دسترسی داشته باشه؟ حدافل تو کد که اینطوری نیست ، اگر هم در کد واقعی هست دیگه نباید اسم کلاس رو اولش بزارید...
من فکر میکنم اگر شما بجای غلط دیکته گرفتن توضیحان من رو میخوندین جوابتون رو میگرفتین.

کدی که مهران نوشته هم درست نیست ، چون با گرفتن یک متغیر گلوبال اونوقت اگر دو نسخه از کامپونتتون ساخته بشه اولین Thread گم میشه!

مهران موسوی
سه شنبه 14 آبان 1387, 00:15 صبح
درسته كدي كه من نوشتم بهينه نيست ولي در كل در يك نسخه از كامپوننت كارت رو راه ميندازه ... من فقط هدفم باز كردن ديد شما براي چگونگي پاس كاري TUSEThread بود . شما ميتوني به صورت بهينه يك نمونه از اون رو توي كلاس Thread ايجاد كني و در هنگام ساخت Thread نمونه ي ساخته شده در Create مربوط به TUSEThread رو به اون نمونه ي موجود در كلاس Thread پاس بدي و در Execute مربوط به Thread هم اون رو به RunProcs پاس بدي تا بتونه ازش استفاده كنه . اينجوري هزار تا نمونه هم از كامپوننتت ساخته بشه ادرس مربوط به Thread قبلي گم نميشه .

اين عمل ميشه همون كاري كه عليرضا گفت ولي شايد چون زياد مطلب رو باز نكرد فكر كنم شما متوجه نشدي .


اگر بازم ابهامي بود بگو با تئوري بالا كد رو بازنويسي كنم بزارم تا متوجه بشي . هر چند فكر كنم فهميدي موضوع از چه قرار هست .

vcldeveloper
سه شنبه 14 آبان 1387, 04:39 صبح
دو کلاس تعریف کردید، یک رویه گلوبال تعریف کردید، یک متد از کلاس اول را در رویه گلوبال بدون اینکه ازش نمونه ایی بسازید، فراخوانی کردید. کلاس دوم را در داخل کلاس اول ساختید، و...

درباره فراخوانی متد Test که علیرضا توضیح دادند؛ یا باید متد Class procedure باشه که بتونید با ارجاع به کلاسش آن را فراخوانی کنید، یا اینکه باید یک نمونه از کلاس را بسازید تا بتونید به متدش دسترسی داشته باشید.
نقش اون رویه گلوبال و اینکه چرا گلوبال هست برای من روشن نیست.
اما درباره کلاسی که از TThread مشتق شده، اگر قراره این Thread توسط کلاس شما که از TComponent امشتق شده، استفاده بشه، آن را در داخل همون کلاس به عنوان یک فیلد تعریف کنید.
دلیل اینکه چرا یک Thread در یک حلقه نامتناهی دائما ساخته و آزاد میشه هم مشخص نیست. ساختن Thread به تعداد زیاد و در فواصل زمانی کم خودش میتونه موجب افزایش سربار برنامه بشه، بطوری که شاید سربار آن بیشتر از افزایش سرعتی باشد که قرار بود از طریق اون Thread بدست بیارید.

بهتر هست درباره کاری که قرار هست Thread شما انجام بده، بیشتر توضیح بدید.

ali_mohamadi8928
سه شنبه 14 آبان 1387, 22:31 عصر
سلام اقاي كشاورز . بابت توضيحاتتون ممنونم .


اما درباره کلاسی که از TThread مشتق شده، اگر قراره این Thread توسط کلاس شما که از TComponent امشتق شده، استفاده بشه، آن را در داخل همون کلاس به عنوان یک فیلد تعریف کنید.

چه جوري ؟



دلیل اینکه چرا یک Thread در یک حلقه نامتناهی دائما ساخته و آزاد میشه هم مشخص نیست. ساختن Thread به تعداد زیاد و در فواصل زمانی کم خودش میتونه موجب افزایش سربار برنامه بشه، بطوری که شاید سربار آن بیشتر از افزایش سرعتی باشد که قرار بود از طریق اون Thread بدست بیارید.


اقاي كشاورز من كه دائما نميسازم و ازادش نميكنم !!!!

همش يك بار اونم در متد Create كلاس اصلي اون رو ميسازم


constructor TUseThread.Create(AnOwner: TComponent);
begin
inherited;
UseThreadPoint:=Self;
fnum := 0;
with TTestThread.Create(TRUE) do begin
Suspended := false;
end;
end;

و بعد چون ميخوام يك رويه رو دائما در يك فاصله ي زماني خاص اجرا كنه در Execute مربوط به Thread يك رويه رو صدا ميزنم كه توش يك حلقه بي نهايت هست و هر بار كه حلقه ميچرخه يك بار يك رويه كه مربوط به كلاس اصلي هست ور صدا ميزنه . با اين كار سعي كردم كار تايمر رو با ThRead شبيه سازي كنم كه مثل اون طي يك باجه ي زماني خاص يك رويه رو پشت سر هم صدا بزنه .

ايا كد زير باعث ميشه در هر بار چرخش حلقه يك نمونه از Thread ساخته بشه ؟؟؟؟


procedure RunProcs;
var
wh: Boolean;
begin

wh := TRUE;

while wh do begin
UseThreadPoint.test;
sleep(1000);
end;

end;


اگه اره چرا اخه ؟؟

چرا Mem Usage برنامه از كم شورع ميشه و كم كم ميره بالاتر ؟؟؟

لطفا راهنمايي كنيد .

در واقع هدف من اينه كه توسط يك Thread كار يك تايمر رو بكنم و طي يك باجه ي زماني خاص پشت سر هم يك رويه از كلاس اصليم رو اجرا كنم تا به Thread اصلي برنامه فشار نياد و سرعت برنامه كم نشه .

لطفا كمك كنيد توي اين زمينه . اگه لطف كنيد علاوه بر توضيحاتتون كد رو هم بر اساس اون توضيحات تغيير بدين خيلي ممنونتون ميشم . اخه شما يكمي علمي ميگين من سر در نميارم . كد رو ببينم منظورتون رو متوجه ميشم .

خيلي ممنون

vcldeveloper
چهارشنبه 15 آبان 1387, 17:59 عصر
چه جوري ؟


TMyClass = class
private
MyThread : TThread;
public
constructor Create;
destructor Destroy; override;
end;

بعد هم MyThread را در داخل متد Create میسازید.


ايا كد زير باعث ميشه در هر بار چرخش حلقه يك نمونه از Thread ساخته بشه ؟؟؟؟
نه، من کد شما را اشتباه خواندم.


در واقع هدف من اينه كه توسط يك Thread كار يك تايمر رو بكنم و طي يك باجه ي زماني خاص پشت سر هم يك رويه از كلاس اصليم رو اجرا كنم تا به Thread اصلي برنامه فشار نياد و سرعت برنامه كم نشه .

یک کلاس Thread جدید بسازید و Timer را در همان کنترل کنید، یا از همون Sleep(1000) در اخل متد Execute آن استفاده کنید.


چرا Mem Usage برنامه از كم شورع ميشه و كم كم ميره بالاتر ؟
با چی چک کردید؟ برای بررسی حافظه مصرفی از Profilerهای موجود استفاده کنید، نه از Task Manager ویندوز که دقت لازم را ندارد. در ضمن، هر حافظه ایی که برنامه از سیستم عامل دریافت میکنه، بالافاصله آن را آزاد نمیکنه، بلکه آن را برای استفاده های بعدی رزرو میکنه، غیر از اینکه سیستم عامل به آن نیاز داشته باشه.

مهران موسوی
چهارشنبه 15 آبان 1387, 20:03 عصر
اقاي محمدي بعد از اعمال تغييراتي كه قبلا ذكر شد كدهاي ويرايش شده ديگه مشكلي ندارن .

فقط شما كاري كه توي پست #6 تاكيد كردم رو يادت نره انجام بدي . اون كار باعث ميشه در صورت ايجاد چند نسخه از كامپوننت هم كدهات دچار مشكل نشه .


در رابطه با سوال اصليت


چرا Mem Usage برنامه از كم شورع ميشه و كم كم ميره بالاتر ؟

ببين به احتمال زياد رويه اي كه توسط Thread دائما صدا زده ميشه داخلش نمونه اي از يك كلاس رو ايجاد ميكني . و در اخر كه استفاده كردي اون رو Free نميكني . اين كار باعث ميشه حافظه براي استفاده هاي بعدي تا زماني كه بهش نياز نباشه ازاد نشه . پس بهتر هست شما حتما در پايان كار نمونه هاي ساخته شده رو free كني .

اين نكته رو به يا داشته باش كه يادت نره براي بهينه تر شدن كدت حتما از بلوكهاي Try .. Finally استفاده كني .

اگه امكان رخ دادن خطايي وجود داره از پردازش استسناء ها هم ميتوني استفاده كني تا در پايان منابع رو ازاد كني .

راستي سعي كن رويه رو در باجه ي زماني بالاي 500 ميلي ثانيه صدا بزني . تا فشار وارد بر پردازنده هم كاهش پيدا كنه .

ali_mohamadi8928
پنج شنبه 16 آبان 1387, 11:43 صبح
نقل قول:
ايا كد زير باعث ميشه در هر بار چرخش حلقه يك نمونه از Thread ساخته بشه ؟؟؟؟
نه، من کد شما را اشتباه خواندم.


اقاي كشاورز خوب شد اشتباه خوندين . اگه واقعا اونجوري بود خيلي بد ميشد . هر چند با عقل جور در نمي امد !



اقا مهران خيلي خيلي ممنونم . بابا تو ديگه كي هستي :تشویق: چون من كلاس ريجستري رو تند درست ميكردم و اخرش ازاد نميكردم اينجوري ميشد . از بلوك try هم استفاده كرم . نه تنها مشكل رفع شد بلكه فكر كنم سرعتش هم زيادتر شد :لبخند:

هم از اقاي كشاورز هم از اقا مهران بابت كمكهاشون متشكرم :خجالت: