PDA

View Full Version : Thread و Freeze شدن برنامه ...



Mahmood_M
یک شنبه 20 اسفند 1385, 22:30 عصر
سلام
من برای پشتیبان گیری از بانکهای اطلاعاتی برنامم ، از یک Thread استفاده کردم ...
این Thread چهار تا Procedure داره ...
یک برای Progress کردن یک Guage ، یکی برای نمایش پیغام ، یکی هم که Finish ( عملیات پایان کار ) ، یکیش هم که Execute ( که Procedure اصلی هستش ) ...
توی رویه Execute ، چند مرحله بک آپ از چند دیتابیس SQL انجام میشه ، بعد از هر بک آپ از هر دیتابیس ، فایل اونها در یک کامپوننتی برای ترکیب فایلها ( AnyFileCollector آقای خلیل زاده ) گنجونده میشن و بعد حذف میشن و همچنین موفقیت آمیز بودن یا عدم موفقیت در ساختن اونها در یک ListBox نوشته میشه و در نهایت فایل اصلی ساخته میشه ، بعد از انجام این مراحل توی رویه نمایش پیغام ، پیغام اتمام کار نشون داده میشه و بعد از اون هم رویه Finish که چند تا دیتابیس Disconnect شده رو دوباره Connect میکنه ( دوتا از دیتابیس ها Access هستند که باید دوباره کانکشن اونها فعال بشه ) ...
مشکل اصلی اینه که توی رویه نمایش پیغام ، که پیغام اتمام کار رو نشون میده ، برنامه قفل میکنه !!! ...
راستش قبلا این طور نمیشد ولی نمی دونم الان مشکلش چیه که این طوری شده ، من قبلا کدی برای نوشتن موفقیت آمیز بودن یا عدم موفقیت کار در یک ListBox ، توی این Thread ننوشته بودم و چیز تازه ای هم که اضافه کردم همین قسمت هست ( نوشتن در یک ListBox ) ولی مشکل اینجاست که با برداشتن این کدها باز هم این مشکل پیش می یاد !! ...

یه سئوال : آیا وقتی ما در یک Thread یک پیغام نشون میدیم ، ( به وسیله تابه Synchronize ) ، اون Thread تا موقع جواب دادن به اون پیغام متوفق می مونه یا نه ( به کارش ادامه میده ) ؟
چون من بعد از نمایش پیغام ، بلافاصله رویه Finish رو اجرا می کنم که توی اون Thread من Terminate میشه ...
یعنی به عبارتی این طوری میشه :

...
Synchronize(ShowMsg);
Synchronize(Finish);

فکر کنم توضیح کامل در مورد مشکلم داده باشم :کف:
با تشکر از همگی ، منتظر جواب دوستان هستم
اگه راهنمایی کنید ممنون میشم ...
با تشکر ...
موفق باشید ...

ghabil
یک شنبه 20 اسفند 1385, 23:01 عصر
اون کدی که میره توی لیست باکس مینویسه رو بزار توی Syncronize چون کلا کاربردش برای VCL هست ، یعنی کامپوننتهای دلفی یعنی هرموقع خواستی بری سراغ کامپونتهای دلفی Syncronize کن نه برای ShowMessage

وقتی ShowMessage میزنه صبر میکنه تا نتیجه بیاد (یعنی کاربر Ok رو بزنه) بعد بقیه Thread اجرا میشه .

vcldeveloper
دوشنبه 21 اسفند 1385, 07:36 صبح
یه سئوال : آیا وقتی ما در یک Thread یک پیغام نشون میدیم ، ( به وسیله تابه Synchronize ) ، اون Thread تا موقع جواب دادن به اون پیغام متوفق می مونه یا نه ( به کارش ادامه میده ) ؟
بله، Synchronize اجرای Thread مربوطه را متوقف می کنه و تابعی که بهش پاس دادید را در Thread اصلی اجرا میکنه. اگر نمی خواید همچین کاری بکنید، باید از روش های همزمان سازی مختلفی که وجود داره استفاده کنید. برای کار شما فکر کنم بهترین چیز استفاده از message ها باشه؛ یعنی Thread در هر مرحله برای گزارش میزان پیشرفت کار یا اتمام کار پیغام هایی را به Thread اصلی ارسال کنه و در Thread اصلی هم یک Message Handler بنویسید که پیغام های دریافت شده را پردازش کنه.

Mahmood_M
سه شنبه 22 اسفند 1385, 14:38 عصر
سلام
با تشکر از دوستان عزیز ...

اون کدی که میره توی لیست باکس مینویسه رو بزار توی Syncronize چون کلا کاربردش برای VCL هست ، یعنی کامپوننتهای دلفی یعنی هرموقع خواستی بری سراغ کامپونتهای دلفی Syncronize کن نه برای ShowMessage

این کار رو کردم ولی باز هم موقع اون کد که میرسه قفل میکنه !!

بله، Synchronize اجرای Thread مربوطه را متوقف می کنه و تابعی که بهش پاس دادید را در Thread اصلی اجرا میکنه. اگر نمی خواید همچین کاری بکنید، باید از روش های همزمان سازی مختلفی که وجود داره استفاده کنید. برای کار شما فکر کنم بهترین چیز استفاده از message ها باشه؛ یعنی Thread در هر مرحله برای گزارش میزان پیشرفت کار یا اتمام کار پیغام هایی را به Thread اصلی ارسال کنه و در Thread اصلی هم یک Message Handler بنویسید که پیغام های دریافت شده را پردازش کنه.

بابت جوابتون ممنونم ...
راستش مشکل رو تا حدودی حل کردم ولی یه مشکل دیگه پیش اومده اینه که وقتی برنامه بسته میشه ، پنجره اون در قسمت نوار فرمان می مونه !!! ( یعنی درواقع بسته نمیشه ) ...
به عکس زیر نگاه کنید ( برنامه بسته شده ولی در قسمت نوار فرمان وجود داره !! ) :
http://mahmoodn.persiangig.com/KDTaskBar.jpg
من Thread فوق رو Terminate می کنم ولی ظاهرا باز هم اثراتی ازش هست ( درضمن Free هم کردم ولی بازم نشد ! )
با تشکر از همگی ...
درضمن ، آقای کشاورز ، می شه در مورد Message Handler که گفتید یه خورده توضیح بدید ، راستش یه چیزهایی فهمیدم ولی به درست بودنش شک دارم ...
فقط یه توضیح کوچیک کارم رو راه می اندازه ...

با تشکر ...
موفق باشید ...

vcldeveloper
چهارشنبه 23 اسفند 1385, 08:49 صبح
می شه در مورد Message Handler که گفتید یه خورده توضیح بدید
شما می تونید برای Thread خودتون یکسری پیام درست کنید، مثلا:


const
WM_THREADMSG := WM_USER + 100;

بعد می تونید در داخل Thread هر جا که لازم بود پیام مربوطه را به پنجره ایی که باید پیشرفت کار Thread را نشان دهد بفرستید:


PostMessage(FormHandle, WM_THREADMSG,0,0);

در فرم مربوطه هم باید یک متد تعریف کنید که پیام مورد نظر را هندل کنه:


private
procedure WmThreadMsgHandler(var Msg: TMessage); message WM_THREADMSG;

و در داخل این متد کاری که باید انجام بشه را انجام بدید، مثلا یک مقدار به ProgressBar بدید.


پنجره اون در قسمت نوار فرمان می مونه !!! ( یعنی درواقع بسته نمیشه ) ...
مطمئن هستید که تمام Thread ها کارشون به اتمام رسیده؟

من Thread فوق رو Terminate می کنم ولی ظاهرا باز هم اثراتی ازش هست
متد Terminate عملا کار خاصی انجام نمیده، فقط خاصیت Terminated را True می کنه. شما باید در کدی برای Thread می نویسید، دائما در مراحل مختلف و در حلقه های مختلف چک کنید که آیا Thread شما Terminate شده یا نه، اگر Terminate شده از متد Execute خارج بشید و سپس Thread را آزاد کنید. برای این منظور باید منتظر وایستید تا متد Execute کارش تموم بشه (با WaitFor)، یا می تونید خصوصیت FreeOnTerminate را True کنید تا Thread پس از اتمام اجرای متد Execute خودش بطور خودکار آزاد بشه.

Mahmood_M
چهارشنبه 23 اسفند 1385, 17:15 عصر
سلام
بابت توضیحات ممنونم ... ( تقریبا درست فهمیده بودم )

متد Terminate عملا کار خاصی انجام نمیده، فقط خاصیت Terminated را True می کنه. شما باید در کدی برای Thread می نویسید، دائما در مراحل مختلف و در حلقه های مختلف چک کنید که آیا Thread شما Terminate شده یا نه، اگر Terminate شده از متد Execute خارج بشید و سپس Thread را آزاد کنید. برای این منظور باید منتظر وایستید تا متد Execute کارش تموم بشه (با WaitFor)، یا می تونید خصوصیت FreeOnTerminate را True کنید تا Thread پس از اتمام اجرای متد Execute خودش بطور خودکار آزاد بشه.
راستش من این کارها رو انجام میدم ، ولی بازم نمیشه ، نمی دونم مشکل کجاست ...
من کد رو میزارم شما یک نگاهی بندازید ...
Thread با کد زیر شروع به کار میکنه :


BT := BackUpThread.Create(True);
BT.FreeOnTerminate := True;
BT.Resume;

و این کد هم مربوط به متد Execute ترد هست :


procedure BackUpThread.Execute;
var
... ( متغیرهای استفاده شده در متد )
begin
if Terminated then
Exit;
try
... ( کدهای مربوط به پشتیبان گیری و ذخیره فایلها )
...
finally
... ( کدهای مربوط به آزادسازی فایلهای ذخیره شده و ... )

Terminate;
end;
end;

من توی کد بالا بعد از عبارت Terminate ، عبارت WaiteFor رو هم نوشتم ولی بازم نشد !!
فکر میکنم که مشکل از همون قسمت آخر باشه ، شاید نباید توی متد Execute خود Thread اون رو Terminate کنم !!
من کدهای بالا رو بدون کدهای قسمت آخر هم نوشتم ولی بازم نشد ( یعنی فقط FreeOnTerminate اون در موقع Create شدن True میشه ) !!!
چه موقع باید Terminate کنم ؟

وقتی فقط FreeOnTerminate رو True میکنم ، بعد از Terminate شدن برنامه ( یعنی Application.Terminate ) ، پنجره Error Reporting باز میشه ( پنجره معروف Dont Send ) و وقتی من دکمه Dont Send رو می زنم چند پیغام پشت سر هم میاد ( پیغام حافظه هست و چیز خاصی توش ننوشته ) و بعد برنامه حذف میشه ... !!!!!!!!!!!!!!!!!!
راستش نمیدونم باید چی کار کنم !!
شما چه راه حلی پیشنهاد میکنید ؟!
استفاده از یک Timer برای چک کردن اتمام کار و بعد Terminate کردن Thread میتونه مناسب باشه ؟!
آیا Suspend کردن Thread میتونه موثر باشه ؟!!

با تشکر از پیگیری شما ...
موفق باشید ...

vcldeveloper
پنج شنبه 24 اسفند 1385, 10:36 صبح
Terminate را در خارج از Thread مربوطه و زمانی که Thread باید متوقف بشه انجام بدید. همونجا هم WaitFor را فراخوانی کنید. در واقع با فراخوانی Terminate مقدار Terminated برابر True میشه و شما باید دائما این مقدار را در داخل Thread چک کنید. با اجرای WaitFor برنامه منتظر میمونه تا Thread به Terminate واکنش نشون بده و کارش رو متوقف کنه.
وقتی کار Thread متوقف شد، میشه Thread را Free کرد. اما اگر FreeOnTerminate فعال باشه، بالافاصله با اتمام کار Thread، شی TThread ساخته شده از حافظه آزاد میشه.

Mahmood_M
پنج شنبه 24 اسفند 1385, 13:17 عصر
سلام

Terminate را در خارج از Thread مربوطه و زمانی که Thread باید متوقف بشه انجام بدید. همونجا هم WaitFor را فراخوانی کنید. در واقع با فراخوانی Terminate مقدار Terminated برابر True میشه و شما باید دائما این مقدار را در داخل Thread چک کنید. با اجرای WaitFor برنامه منتظر میمونه تا Thread به Terminate واکنش نشون بده و کارش رو متوقف کنه.
وقتی کار Thread متوقف شد، میشه Thread را Free کرد. اما اگر FreeOnTerminate فعال باشه، بالافاصله با اتمام کار Thread، شی TThread ساخته شده از حافظه آزاد میشه.
من برنامه نمونه شما رو که در مورد Thread بود نگاه کردم ...
توی اون برنامه ( که برای کپی فایل بود ) ، اگه روی دکمه Cancel کلیک نشه ، Thread به کارش ادامه میده و Terminate نمیشه ، یعنی جایی با کد نویسی Terminate اش نمیکنیم ، و چون FreeOnTerminate اون True هست ، پس بعد از اتمام کار خودش Terminate میشه ...
من هم نیازی به Terminate کردن Thread ندارم ( مثلا لازم نیست بعد با انجام یک عمل ( مثلا زدن دکمه Cancel در برنامه نمونه شما ) ، Thread رو Terminate کنم ) ...
من میخوام بعد از اتمام کار خودش Terminate بشه ، برای این کار هم توی شروع به کار اون FreeOnTerminate اش رو True میکنم ...
ولی مشکل اینه که وقتی برنامه من بسته میشه ، پیغامی که بالا گفتم ( Error Reporting ) ظاهر میشه !!!
خوب با کاری که من کردم ( درست مثل همون برنامه نمونه شما ) نباید چنین اتفاقی بیافته ولی ...
فکر کنم مشکل این باشه که Thread من در متد Execute به خوبی Terminate شدن Thread رو چک نمی کنه تا خارج بشه ... !!
توی کدی که بالا نوشتم ، فقط اول کد ، این کد رو نوشتم که چک کنه ...
اگه وسط کار چک کنه و خارج بشه ، به مشکل بر میخورم ، چون ممکنه چند تا جدول رو غیرفعال کرده باشه و بعد ادامه نده و خارج بشه ( که البته میشه با چک کردن اونها مشکل رو رفع کرد ( مثلا اگه غیر فعال بود دوباره فعال بشه ) ) ، ولی راه دیگه ای نیست ؟، به نظر شما تنها مشکلش همینه ، آیا اگه فقط اول کد چک کنیم که ترد Terminate شده یا نه کافی نیست ؟!
با تشکر از جوابهاتون ...
موفق باشید ...

vcldeveloper
جمعه 25 اسفند 1385, 08:30 صبح
آیا اگه فقط اول کد چک کنیم که ترد Terminate شده یا نه کافی نیست ؟!
نه، اگه Thread شما در داخل یک حلقه باشه، یا در حال انجام یک پردازش سنگین، در این صورت هیچ وقت متوجه نمیشه که خصوصیت Terminated = True شده و باید به اجرای خودش خاتمه بده. شما باید سورس Thread را به گونه ایی تغییر بدید که مرتبا مقدار ، Terminated چک بشه.

Mahmood_M
جمعه 25 اسفند 1385, 16:29 عصر
سلام
با عرض معذرت به خاطر سئواهای پی در پی ...
راستش آخر نشد ...
من سورسش رو میزارم ، اگه میشه اصلاحش کنید :
این سورس OnExecute مربوط به Thread :


procedure BackUpThread.Execute;
var
Prog : Integer;
begin

if Terminated then
Exit;

try
DetailForm.ListBox1.Clear;
BckFile := TAnyFile.Create(TAnyFileItem);
Info := TIniFile.Create(BackUpForm.Edit1.Text + '\Info.ini');
with BackUpForm do
begin
if AezaCheck.Checked = True then
begin
if Terminated then
Exit;
try
BckPath := Edit1.Text + '\AezaBank.Abck';
Form2.ADOCommand1.CommandText := 'USE MASTER';
Form2.ADOCommand1.Execute;
Form2.ADOCommand1.CommandText := 'BACKUP DATABASE memb TO DISK = '+QuotedStr(BckPath);
Form2.ADOCommand1.Execute;
AezaBackedUp := True;
except
AezaBackedUp := False;
DeleteFile(BckPath);
MsgText := 'ãÔ˜á& ÇÓÊ
MessageBox(BackUpForm.Handle, Pchar(MsgText), '', MB_OK+MB_ICONEXCLAMATION);
end;
{Progress}
for Prog := 0 to 15 do
begin
Synchronize(Progress);
end;
{end Progress}
if Terminated then
Exit;
if AezaBackedUp = True then
begin
try
FAeza := BckFile.Add;
FAeza.Stream.LoadFromFile(BckPath);
Info.WriteInteger('Aeza', 'Aeza', FAeza.ID);
DeleteFile(BckPath);
except
AezaBackedUp := False;
DeleteFile(BckPath);
MsgText := 'ãÔ˜áí ÏÑ
MessageBox(BackUpForm.Handle, Pchar(MsgText), '', MB_OK+MB_ICONEXCLAMATION);
end;
end;
end;
{Progress}
for Prog := 15 to 30 do
begin
Synchronize(Progress);
end;
{end Progress}
if Terminated then
Exit;
if EhdayeeCheck.Checked = True then
begin
try
BckPath := Edit1.Text + '\EhdaBank.EBck';
Form21.ADOCommand1.CommandText := 'USE MASTER';
Form21.ADOCommand1.Execute;
Form21.ADOCommand1.CommandText := 'BACKUP DATABASE KE TO DISK = '+QuotedStr(BckPath);
Form21.ADOCommand1.Execute;
EhdaBackedUp := True;
except
EhdaBackedUp := False;
MsgText := 'ãÔ˜áí ÏÑ
MessageBox(BackUpForm.Handle, Pchar(MsgText), '', MB_OK+MB_ICONEXCLAMATION);
end;
if EhdaBackedUp = True then
begin
try
FEhda := BckFile.Add;
FEhda.Stream.LoadFromFile(BckPath);
Info.WriteInteger('Ehda', 'Ehda', FEhda.ID);
DeleteFile(BckPath);
except
EhdaBackedUp := False;
DeleteFile(BckPath);
MsgText := 'ãÔ˜áí Ï&Ntilde
MessageBox(BackUpForm.Handle, Pchar(MsgText), '', MB_OK+MB_ICONEXCLAMATION);
end;
end;
end;
{Progress}
for Prog := 30 to 45 do
begin
Synchronize(Progress);
end;
{end Progress}
if Terminated then
Exit;
if MojoodCheck.Checked = True then
begin
try
BckPath := Edit1.Text + '\MojBank.MBck';
Form9.ADOCommand1.CommandText := 'USE MASTER';
Form9.ADOCommand1.Execute;
Form9.ADOCommand1.CommandText := 'BACKUP DATABASE KM TO DISK = '+QuotedStr(BckPath);
Form9.ADOCommand1.Execute;
MojoodBackedUp := True;
except
MojoodBackedUp := False;
MsgText := 'ãÔ˜áí ÏÑ
MessageBox(BackUpForm.Handle, Pchar(MsgText), '', MB_OK+MB_ICONEXCLAMATION);
end;
if MojoodBackedUp = True then
begin
try
FMojood := BckFile.Add;
FMojood.Stream.LoadFromFile(BckPath);
Info.WriteInteger('Mojood', 'Mojood', FMojood.ID);
DeleteFile(BckPath);
except
MojoodBackedUp := False;
DeleteFile(BckPath);
MsgText := 'ãÔ˜áí ÏÑ
MessageBox(BackUpForm.Handle, Pchar(MsgText), '', MB_OK+MB_ICONEXCLAMATION);
end;
end;
end;
{Progress}
for Prog := 45 to 60 do
begin
Synchronize(Progress);
end;
{end Progress}
if Terminated then
Exit;
if AmanatCheck.Checked = True then
begin
try
BckPath := Edit1.Text + '\AmBank.ABck';
Form1.ADOCommand1.CommandText := 'USE MASTER';
Form1.ADOCommand1.Execute;
Form1.ADOCommand1.CommandText := 'BACKUP DATABASE RP TO DISK = '+QuotedStr(BckPath);
Form1.ADOCommand1.Execute;
AmantiBackedUp := True;
except
AmantiBackedUp := False;
MsgText := 'ãÔ˜áí ÏÑ
MessageBox(BackUpForm.Handle, Pchar(MsgText), '', MB_OK+MB_ICONEXCLAMATION);
end;
if AmantiBackedUp = True then
begin
try
FAmanti := BckFile.Add;
FAmanti.Stream.LoadFromFile(BckPath);
Info.WriteInteger('Amanat', 'Amanat', FAmanti.ID);
DeleteFile(BckPath);
except
AmantiBackedUp := False;
DeleteFile(BckPath);
MsgText := 'ãÔ˜áí ÏÑ
MessageBox(BackUpForm.Handle, Pchar(MsgText), '', MB_OK+MB_ICONEXCLAMATION);
end;
end;
end;
{Progress}
for Prog := 60 to 75 do
begin
Synchronize(Progress);
end;
{end Progress}
if Terminated then
Exit;
if Modiriatcheck.Checked = True then
begin
try
Form4.ADOConnection1.Connected := False;
FModir := BckFile.Add;
FModir.Stream.LoadFromFile(ExtractFilePath(Applica tion.ExeName)+'\AK.mdb');
Info.WriteInteger('MK', 'MK', FModir.ID);
ModirBackedUp := True;
except
ModirBackedUp := False;
MsgText := 'ãÔ˜áí ÏÑ
MessageBox(BackUpForm.Handle, Pchar(MsgText), '', MB_OK+MB_ICONEXCLAMATION);
end;
end;
{Progress}
for Prog := 75 to 90 do
begin
Synchronize(Progress);
end;
{end Progress}
if Terminated then
Exit;
if IntCheck.Checked = True then
begin
try
Form16.ADOConnection1.Connected := False;
FInternet := BckFile.Add;
FInternet.Stream.LoadFromFile(ExtractFilePath(Appl ication.ExeName)+'\InH.mdb');
Info.WriteInteger('Int', 'Int', FInternet.ID);
InterBackedUp := True;
except
InterBackedUp := False;
MsgText := 'ãÔ˜áí ÏÑ
MessageBox(BackUpForm.Handle, Pchar(MsgText), '', MB_OK+MB_ICONEXCLAMATION);
end;
end;
{Progress}
for Prog := 90 to 100 do
begin
Synchronize(Progress);
end;
{end Progress}
if Terminated then
Exit;
end;
finally
FIni := BckFile.Add;
FIni.Stream.LoadFromFile(BackUpForm.Edit1.Text +'\Info.ini');
DeleteFile(BackUpForm.Edit1.Text + '\Info.ini');
try
BckFile.SaveToFile(BackUpForm.Edit1.Text + '\KDBackUp.KDB1');
except
MsgText := 'ÝÇíá
MessageBox(BackUpForm.Handle, Pchar(MsgText), '', MB_OK+MB_ICONERROR);
end;
MsgText := 'ÚãáíÇÊ
MessageBox(BackUpForm.Handle, Pchar(MsgText), '', MB_OK+MB_ICONINFORMATION);
Synchronize(Finish);
end;
end;

( حروف فارسی نا مفهوم شده ! ) ...
من کد مربوط به چک کردن Terminate شدن Thread رو وسط کد نوشتم ولی هنوز کدهای مربوط به چک کردن و دوباره فعال کردن یا ... رو ننوشتم ...
می دونم بررسی این سورس کار وقت گیریه ولی اگه این کار رو بکنید خیلی ممنون میشم ...
با تشکر ...
منتظرم ...

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

vcldeveloper
شنبه 26 اسفند 1385, 10:03 صبح
کد چک کردن Terminated را داخل حلقه ها و همچنین قبل از اجرای دستورات وقت گیر قرار بدید. دقت کنید که اگر شی خاصی میسازید یا اطلاعات خاصی را تغییر میدید، قبل از خروج از Thread تکلیف اونها را روشن کنید.
در صورتی که به درستی مقدار Terminated در Thread چک بشه، با اجرای BackupThread.Terminate مقدار Terminated = True میشه و Thread هم متوجه اون میشه و به اجرای خودش خاتمه میده. همچنین چون FreeOnTerminate = True هست، با اتمام کار Thread، نمونه ساخته شده از اون از حافظه آزاد میشه. البته چون BackupThread.Terminate بالافاصله موجب قطع کار Thread نمیشه، با توجه به دستورات در حال اجرا در Thread، چند لحظه زمان میبره تا Thread آزاد بشه. برای این منظور باید از متد WaitFor شی Thread ایجاد شده استفاده کنید. WaitFor تا زمانی که اجرای Thread خاتمه پیدا کنه، اجرای برنامه را متوقف می کنه. در این صورت می تونید مطمئن بشید که Thread بدرستی خاتمه پیدا کرده.

Mahmood_M
دوشنبه 28 اسفند 1385, 15:32 عصر
سلام

کد چک کردن Terminated را داخل حلقه ها و همچنین قبل از اجرای دستورات وقت گیر قرار بدید. دقت کنید که اگر شی خاصی میسازید یا اطلاعات خاصی را تغییر میدید، قبل از خروج از Thread تکلیف اونها را روشن کنید.
در صورتی که به درستی مقدار Terminated در Thread چک بشه، با اجرای BackupThread.Terminate مقدار Terminated = True میشه و Thread هم متوجه اون میشه و به اجرای خودش خاتمه میده. همچنین چون FreeOnTerminate = True هست، با اتمام کار Thread، نمونه ساخته شده از اون از حافظه آزاد میشه. البته چون BackupThread.Terminate بالافاصله موجب قطع کار Thread نمیشه، با توجه به دستورات در حال اجرا در Thread، چند لحظه زمان میبره تا Thread آزاد بشه. برای این منظور باید از متد WaitFor شی Thread ایجاد شده استفاده کنید. WaitFor تا زمانی که اجرای Thread خاتمه پیدا کنه، اجرای برنامه را متوقف می کنه. در این صورت می تونید مطمئن بشید که Thread بدرستی خاتمه پیدا کرده.
بابت توضیحات واقعا ممنونم ...
من جواب یک سئوالم رو هنوز نگرفتم ...
توی برنامه ی نمونه ای که شما گذاشته بودید ، در هنگام کپی فایل کدی برای Terminate شدن Thread انجام نمیشه !! ، و Thread موقعی Terminate میشه که ما بخوام کپی فایل رو متوقف کنیم ...
برنامه من هم همینطور هست ، من نمیخوام اون رو متوقف کنم ، فقط میخوام مثل همون کپی فایل ( که شما گذاشته بودید ) ، Thread من کارش رو انجام بده ، توی برنامه شما بعد از پایان کار ، Thread هم کارش تموم میشه و برنامه بدون مشکل بسته میشه ، ولی برنامه من موقع بسته شدن Error میده ( همون پنجره Error Reporting ) !!!
این کدیه که شما توی برنامه نمونتون نوشته بودید :

procedure Test.Execute;
var
R : integer;
begin
if not FileExists(Source) then
begin
Synchronize(ErrMessage);
Exit;
end;
//This is not a good way to copy files, especially for small files.
// This is just for testing threading in Delphi
AssignFile(SFile,Source);
AssignFile(DFile,Dest);
try
Reset(SFile,1);
Rewrite(DFile,1);
Synchronize(InitGauge);
while (not EOF(SFile)) do
begin
if Terminated then
Break;
BlockRead(SFile,Buffer,sizeof(Buffer),R);
if R <> 0 then
begin
BlockWrite(DFile,Buffer,sizeof(Buffer),R);
Synchronize(UpdateGauge);
end;
end;
finally
Synchronize(FinishJob);
closeFile(SFile);
closeFile(DFile);
end;
end;
در کد بالا فقط یک کد برای چک کردن در حلقه While قرار داره که فکر میکنم برای متوقف کردن عملیات کپی هست ( وقتی که روی دکمه Cancel کلیک بشه ) ...
خوب اگه Thread در برنامه من متوقف نشه ، نیازی به این کد نیست و باید درحالت عادی بعد از اتمام کارش ( در متد OnExecute ) ، خودش هم از بین بره ...
پس چرا این اتفاق نمی افته ؟!!!

برای وقتی که روی جواب دادن به سئوالات من میزارید واقعا ممنونم ...
فکر کنم سئوالم رو خوب بیان کرده باشم ...
منتظر جوابتون هستم ...
موفق باشید ... ( سال نوتون هم مبارک ) ...

vcldeveloper
سه شنبه 29 اسفند 1385, 10:45 صبح
اگر FreeOnTerminate = True باشه با اتمام اجرای OnExecute شی Thread ایجاد شده آزاد میشه. در کد بالا ما فقط یک حلقه ساده داریم، و یک بار چک کردن Terminated در داخل حلقه کافی بود. کد شما پیچیده تر هست و از حلقه های بیشتری استفاده کرده، پس باید تعداد چک کردن Terminated هم بیشتر باشه.
اگر در زمان بسته شدن برنامه، Thread هایی که ایجاد کردید، هنوز مشغول کار باشند، در اون صورت ممکنه براتون مشکل پیش بیاد. همونطور که قبلا گفتم، شما باید قبل از بستن برنامه تمام Thread های در حال اجرا را Terminate کنید و با استفاده از متد WaitFor هر یک از Thread ها منتظر پایان اجرای Thread با شید.
من دقیقا نمی دونم که آیا پیغام خطایی که شما بهش اشاره می کنید، مربوط به استفاده از Thread ها هست یا نه، و اگر هست مربوط به چه قسمتی از Thread.
اون برنامه ایی هم که اشاره کردید من قبلا به عنوان نمونه نوشتم، الان خاطرم نیست، اگه میشه لینکش را بزارید.

موفق باشید،
سال نو خوشی داشته باشید.

Mahmood_M
چهارشنبه 01 فروردین 1386, 07:28 صبح
سلام
با عرض شرمندگی و تشکر فراوان به خاطر جوابهاتون ...

اگر FreeOnTerminate = True باشه با اتمام اجرای OnExecute شی Thread ایجاد شده آزاد میشه
خوب ، True هست ...

در کد بالا ما فقط یک حلقه ساده داریم، و یک بار چک کردن Terminated در داخل حلقه کافی بود. کد شما پیچیده تر هست و از حلقه های بیشتری استفاده کرده، پس باید تعداد چک کردن Terminated هم بیشتر باشه.

سئوال اصلی من هم همینه ، چرا باید Terminated چک بشه ؟! ، مگه چک کردن برای این نیست که اگه وسط کار خودمون Thread رو Terminate کردیم ، از Execute اون خارج بشیم ، ولی من نمیخوام Thread رو خودم Terminate کنم ( چون نیازی به Cancel کردن کار اون نیست ) ، میخوام خودش بعد از اتمام کار آزاد بشه ...

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

من مطمئنم که پیغام به خاطر همین Thread هست ...

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

فایل زیر حاوی دوتا پروژه است که هردو درواقع همون برنامه نمونه ای هستن که شما گذاشتید ، ولی یکیش رو من دستکاری کردم ، یعنی فقط کد مربوط به چک کردن Terminate شدن Thread رو برداشتم ، بدون اون کد هم برنامه به راحتی خاتمه پیدا میکنه ، لطفا فایل زیر رو دانلود کنید و پروژه ها رو مقایسه کنید ...
اینم لینک دانلود :
http://rapidshare.com/files/22036602/ThreadExamples.rar.html
بازم به خاطر جوابهاتون ممنونم ...
با تشکر و آرزوی موفقیت در سال جدید برای شما ...
موفق باشید ...

vcldeveloper
پنج شنبه 02 فروردین 1386, 08:20 صبح
سئوال اصلی من هم همینه ، چرا باید Terminated چک بشه ؟! ، مگه چک کردن برای این نیست که اگه وسط کار خودمون Thread رو Terminate کردیم ، از Execute اون خارج بشیم ، ولی من نمیخوام Thread رو خودم Terminate کنم ( چون نیازی به Cancel کردن کار اون نیست ) ، میخوام خودش بعد از اتمام کار آزاد بشه ...
شما باید مقدار Terminated را چک کنید، چون در غیر اینصورت شما نمی دونید که اجرای Thread مربوطه به پایان میرسه و این موجب ایجاد مشکل در برنامه میشه. مثلا آیا در هنگام بسته شدن برنامه، شما می دونید که آیا اجرای Thread مربوطه یا سایر Thread ها به اتمام رسیده یا نه؟! مشکلی که پیش میاد به این صورته:
کاربر سعی میکنه برنامه را ببنده، برنامه بدون چک کردن اینکه آیا Thread ایی در حال اجرا هست یا نه، سعی در آزاد کردن فرم اصلی برنامه و کنترل های اون میکنه، در حالی که Thread مربوطه در حال اجرا شدن هست و هر لحظه در حال ارسال اطلاعات به فرم اصلی برای نمایش وضعیت اجرا به کاربر هست. در همچین حالتی، وقتی فرمی وجود نداره، Thread داده های خودش را به کجا ارسال میکنه؟! نتیجه اش این میشه که Access Violation می گیرید! البته ممکنه همیشه این اتفاق نیوفته و گاهی Thread در زمان بسته شدن برنامه در حال اجرا نباشه، یا داده خاصی با سایر اجزاء برنامه رد و بدل نکنه، اما شما باید حالت های مختلف را در برنامه تون پیش بینی بکنید.
سوال دیگه احتمالا اینه که آیا با چک کردن مقدار Terminated در داخل Thread و Terminate کردن Thread در زمان بسته شدن برنامه، مشکل حل میشه؟
جوابش هم اینه که نه، باید قبل از آزاد کردن فرم، یا هر بخش دیگه ایی از برنامه که Thread به اون داده اراسال میکنه، مطمئن بشیم که اجرای Thread تمام شده. برای همین هم از متد WaitFor استفاده میکنیم. چون ما نمی دونیم در زمان Terminate کردن Thread، اون Thread در چه مرحله ایی از اجرا قرار داره و کی اجرای خودش رو به پایان میرسونه. اگر صرفا Thread مربوطه را Terminate کنیم و بالافاصله فرم مورد نظر را آزاد کنیم، ممکنه در این فاصله هنوز اجرای Thread متوقف نشده باشه و این مسئله برای ما مشکل ایجاد کنه.


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

Mahmood_M
پنج شنبه 02 فروردین 1386, 18:31 عصر
سلام
به خاطر توضیحات کامل ممنون ...
جواب اصلی رو گرفتم ...
فقط یه مشکل کوچیک وجود داره ( راه حل براش زیاده ولی میخوام نظر شما رو هم بدونم ) :
شما گفتید که توی خود متد OnExecute اون رو Terminate نکنم ...
بهترین زمان برای Terminate کردن Thread چه وقت هست ؟
چون جوریه که نمی شه مثلا یک دکمه برای پایان کار گذاشت و یا ...
مثلا یه راه حلش اینه که من یه متغیر به نام ( مثلا ) Finished از نوع Boolean تعریف کنم و در پایان کار Thread اون متغیر رو True کنم و با یک تایمر چک کنم که هر موقع مقدارش True شد ، Thread رو Terminate کنم و بعد اون رو False کنم ...
امیدوارم خوب توضیح داده باشم ...
به نظر شما این راه منطقیه ؟ ، شما چه راهی پیشنهاد می کنید ؟!

با تشکر و عرض معذرت ، ( قول می دم سئوال آخر باشه !!! )

منتظرم و موفق باشید ...

vcldeveloper
جمعه 03 فروردین 1386, 02:17 صبح
شما گفتید که توی خود متد OnExecute اون رو Terminate نکنم
آخه چه لزومی داره این کار را بکنید؟! با خروج از OnExecute اجرای Thread خاتمه پیدا میکنه و Terminate میشه، اگر می خواید در OnExecute همچین کاری بکنید، فقط کافیه از OnExecute خارج بشید (مثلا با Exit).

بهترین زمان برای Terminate کردن Thread چه وقت هست ؟
این دیگه بستگی به شما و برنامه شما داره. ممکنه بخواید به کاربر اجازه بدید اجرای Thread را متوقف کنه، ممکنه لازم باشه قبل از آزاد کردن Thread داده هایی با Thread رد و بدل بشه و...
Thread شما باید آمادگی داشته باشه که هر زمان شما ازش خواستید بتونید به سرعت به کار خودش خاتمه بده. من نمی دونم بهترین زمان برای Terminate کردن اون کی می تونه باشه.
اما می دونم که قبل از خروج از برنامه باید Thread هایی که هنوز مشغول هستند را بنوعی متوقف کنید.
اگر می خواید صرفا چک کنید که آیا اجرای Thread خاتمه پیدا کرده یا نه، می تونید از Thread بخواید در انتهای OnExecute پیغامی به Thread اصلی مبنی بر اتمام کار ارسال کنه.