View Full Version : در چه مواردی از متد Synchronize استفاده کنم ؟
مهران رسا
یک شنبه 05 اردیبهشت 1389, 12:14 عصر
سلام
این قطعه کدی هست که برای استفاده از Threadها نوشته شده :
procedure MyTr.PBar;
var
i: integer;
begin
Form1.ProgressBar1.Max := 1000000;
for i := 1 to 1000000 do
begin
Form1.ProgressBar1.Position := i;
end;
end;
procedure MyTr.Execute;
begin
PBar;
end;
بار اول متد PBar رو با استفاده از Synchronize فراخوانی کردم . اما در حالی که انتظار داشتم با کدهای بالا (استفاده از Thread) نتیجه ای شبیه عملکرد Application.ProcessMessages داشته باشم اینطور نشد و همون حالت معروف وقفه در فرم اتفاق افتاد . اما بدون استفاده از متد Synchronize همچین مشکلی وجود نداره ! علتش چیه ؟
Mahmood_M
یک شنبه 05 اردیبهشت 1389, 13:27 عصر
با فراخوانی متد Synchronize ، اجرای Procedure فراخوانی شده به Thread اصلی برنامه واگذار می شه ، یعنی Thread اصلی Suspend میشه و Thread ساخته شده توسط شما به عنوان جزئی از Thread اصلی برنامه عمل می کنه و Procedure رو اجرا میکنه ، پس در هنگام اجرای Procedure توسط Synchronize ، چون Thread اصلی برنامه Suspend شده نمی تونه پیغامهای دیگه رو دریافت کنه و در نتیجه نمی تونه GUI رو آپدیت کنه و اصطلاحا هنگ می کنه ...
کار Synchronize اینه که به Thread ساخته شده اجازه بده به عنوان جزئی از Thread اصلی به GUI دسترسی داشته باشه ، شما باید Procedure رو به صورت زیر تغییر بدید :
type
MyThread = class(TThread)
procedure DoProgress;
procedure Execute; override;
end;
...
procedure MyThread.Execute;
var
i: integer;
begin
Form1.ProgressBar1.Max := 1000000;
for i := 1 to 1000000 do
begin
Synchronize(DoProgress);
end;
end;
procedure MyThread.DoProgress;
begin
Form1.ProgressBar1.Position := Form1.ProgressBar1.Position + 1;
end;
procedure TForm1.BitBtn1Click(Sender: TObject);
var
M : MyThread;
begin
M := MyThread.Create(True);
M.FreeOnTerminate := True;
M.Resume;
end;
موفق باشید ...
مهران رسا
یک شنبه 05 اردیبهشت 1389, 14:07 عصر
ممنون از راهنماییتون .
در قسمتی از برنامه نیاز دارم تا از کنترل TIDHttp استفاده کنم . این کنترل تابعی به نام Get داره که با ارسال پارامتری با محتوای یک URL میتونیم سورس (کدهای HTML) صفحه مورد نظر رو به صورت رشته دریافت کنیم .
در زمان استفاده از این تابع و در هنگام دریافت سورس صفحه Html همون حالت هنگ کردن در فرم به وجود میاد . با توجه به اینکه به کدهای این تابع دسترسی نداریم ، چطور میشه ضمن استفاده از متد Synchronize از این حالت جلوگیری کرد ؟ و یا اصلاً نیاز هست از Synchronize استفاده بشه ؟
اصلاً هدف از ایجاد Thread اینه که برنامه به چندین قسمت موازی تقسیم بندی بشه و به صورت مجزا اجرا بشه . و همونطور که شما گفتید Synchronize نهایتاً Thread مورد نظر رو به Thread اصلی برنامه پاس میده .
ضمناً دلیل استفاده از متد Synchronize هنگام کار با اجزای فرم چیه ؟
در برخی موارد دچار سردرگمی شدم . ممنون میشم راهنمایی بفرمایید.
Mahmood_M
یک شنبه 05 اردیبهشت 1389, 16:15 عصر
در زمان استفاده از این تابع و در هنگام دریافت سورس صفحه Html همون حالت هنگ کردن در فرم به وجود میاد . با توجه به اینکه به کدهای این تابع دسترسی نداریم ، چطور میشه ضمن استفاده از متد Synchronize از این حالت جلوگیری کرد ؟ و یا اصلاً نیاز هست از Synchronize استفاده بشه ؟
چنین مواردی باید درون Thread ساخته شده انجام بشه ، نیازی هم به استفاده از Synchronize نیست !
یک نمونه براتون درست کردم و ضمیمه کردم ، اون رو بررسی کنید ، هرجایی به مشکل برخورد کردید بگید تا راهنمایی کنم ، به این موضوع که اشیائی که صاحبشون Thread ساخته شده هست دارن دستورات رو اجرا می کنن دقت کنید ...
اصلاً هدف از ایجاد Thread اینه که برنامه به چندین قسمت موازی تقسیم بندی بشه و به صورت مجزا اجرا بشه . و همونطور که شما گفتید Synchronize نهایتاً Thread مورد نظر رو به Thread اصلی برنامه پاس میده .
ضمناً دلیل استفاده از متد Synchronize هنگام کار با اجزای فرم چیه ؟
کار اصلی Synchronize برای دسترسی به اجزایی از Thread اصلی برنامه هست که به GUI برنامه ربط دارن ، هر موقع نیاز به انجام عملیاتی وقت گیر بود و این عملیات روی اشیاء ظاهری برنامه تاثیر گذار بود پیشنهاد اینه که از Synchronize استفاده کنید ...
همونطور که گفتم وقتی Synchronize فراخوانی میشه Thread اصلی برنامه متوقف میشه و درخواستی که توسط Synchronize ارسال شده رو انجام میده ، همونطور که می دونید هیچ دو Thread ای در ویندوز در یک لحظه همزمان عملیاتی رو انجام نمی دن ، پس اگر بخوایم خیلی ساده توضیح بدیم ، وقتی از Synchronize استفاده نشه ، Thread ساخته شده نمی تونه عملیاتش رو بر روی اشیاء انجام بده تا زمانی که Thread اصلی مسئولیت نگهداری اشیاء رو بر عهده داره و متوقف نشده ...
برنامه ضمیمه رو ببینید ، به درک بهتر نحوه ی کار Thread کمک می کنه ...
موفق باشید ...
vcldeveloper
یک شنبه 05 اردیبهشت 1389, 16:58 عصر
با فراخوانی متد Synchronize ، اجرای Procedure فراخوانی شده به Thread اصلی برنامه واگذار می شه ، یعنی Thread اصلی Suspend میشه و Thread ساخته شده توسط شما به عنوان جزئی از Thread اصلی برنامه عمل می کنه و Procedure رو اجرا میکنه ، پس در هنگام اجرای Procedure توسط Synchronize ، چون Thread اصلی برنامه Suspend شده نمی تونه پیغامهای دیگه رو دریافت کنه و در نتیجه نمی تونه GUI رو آپدیت کنه و اصطلاحا هنگ می کنه ...
نه، این توضیح از نظر فنی دقیق نیست...
Thread اصلی با فراخوانی Synchronize به صورت Suspend در نمیاد. وقتی Synchronize اجرا میشه، Threadایی که متد Synchronize رو اجرا کرده، Suspend میشه، و کد تحویل داده شده به متد Synchronize در داخل Thread اصلی اجرا میشه. پس این Thread اصلی نیست که متوقف میشه.
Synchronization یکی از عملیات های رایج در برنامه های Multi-threaded هست، و منظور از آن هم به طور ساده همزمان سازی اجرای دو یا چند Thread در مراحل خاصی از اجرای برنامه، یا متوالی کردن دسترسی به برخی داده های اشتراکی هست. برای Synchronize کردن Threadها ابزارها و تکنیک های مختلفی وجود دارند. یکی از این ابزارها متد TThread.Synchronize هست. هر سیستم عاملی تعدادی ابزار اولیه برای Synchronization ارائه میکنه (مثل Mutex، Critical Sections, Semaphore، و غیره).
در ویندوز کنترل های بصری (مثل دکمه ها، لیست ها، و غیره) باید توسط همان Threadایی که آنها را ساخته تغییر داده بشند. در نتیجه اگر Thread ایی یک کنترلی را ساخت، Thread دیگه نباید آن کنترل را تغییر بده. در VCL دلفی محدودیت کمی بیشتر هست؛ به این صورت که کنترل ها همیشه توسط Thread اصلی تغییر داده میشند.
همونطور که می دونید هیچ دو Thread ای در ویندوز در یک لحظه همزمان عملیاتی رو انجام نمی دن
این فقط برای CPUهای تک هسته ایی صادق هست، و برای CPUهای چند هسته ایی، یا سیستم های دارای چند CPU صدق نمیکنه.
در زمان استفاده از این تابع و در هنگام دریافت سورس صفحه Html همون حالت هنگ کردن در فرم به وجود میاد . با توجه به اینکه به کدهای این تابع دسترسی نداریم ، چطور میشه ضمن استفاده از متد Synchronize از این حالت جلوگیری کرد ؟ و یا اصلاً نیاز هست از Synchronize استفاده بشه ؟
کدهای مربوط به کلاس TIdHttp و متد Get آن در دسترس عموم هستند، چون اینها بخشی از مجموعه Indy هستند که کتابخانه ایی Open-source برای کار با پروتکل های اینترنت هست. برای دیدن سورس یک کلاس یا یک متد در دلفی، کافیه کلید Ctrl را نگهدارید، و روی عبارت مربوطه کلیک کنید.
در کار با Indy باید دقت کنید که کتابخانه Indy به صورت blocking mode با شبکه کار میکنه؛ یعنی دسترسی به منابع شبکه به صورت غیرهمزمان صورت نمیگیره. این کار باعث میشه که نوشتن برنامه های تحت شبکه با Indy تا حد بسیار زیادی ساده بشه. البته در دلفی همواره امکان استفاده مستقیم از WinSock که به صورت non-blocking عمل میکنه، وجود داره.
پس Indy برای اجرای متد Get، از Thread فعلی استفاده میکنه. اگر شما نمی خواید که Thread اصلی برنامه درگیر این کار بشه، باید یک Thread مستقل ایجاد کنید، و عملیات مربوطه را در همان Thread انجام بدید. هر زمان که آن Thread کارش را تمام کرد، میتونه نتیجه عملیات را به Thread اصلی برگردونه. مثلا در انتهای متد Execute مربوط به Thread ساخته شده، می تونید مقدار برگشتی متد Get رو با استفاده از متد Synchronize به Thread اصلی بفرستید.
البته اگر مشکلتون صرفا هنگ کردن رابط کاربر برنامه هست، و میخواید این حالت هنگ کردن وجود نداشته باشه، یک راه ساده تر اینه که یک کامپوننت IdAntiFreeze از مجموعه Indy را روی فرم بیاندازید، و آن را فعال کنید. IdAntiFreeze باعث میشه در زمانی که Thread اصلی منتظر دریافت پاسخ از شبکه هست، Application.ProcessMessage فراخوانی بشه.
Mahmood_M
یک شنبه 05 اردیبهشت 1389, 17:34 عصر
Thread اصلی با فراخوانی Synchronize به صورت Suspend در نمیاد. وقتی Synchronize اجرا میشه، Threadایی که متد Synchronize رو اجرا کرده، Suspend میشه، و کد تحویل داده شده به متد Synchronize در داخل Thread اصلی اجرا میشه. پس این Thread اصلی نیست که متوقف میشه.
مطمئنید ؟! ، ولی به نظرم اینطور نیست و Thread اصلی متوقف میشه ، الآن کمی توی گوگل گشتم و این صفحه (http://www.delphicorner.f9.co.uk/articles/db1.htm) رو پیدا کردم ، توضیحاتش در مورد Synchronize رو بخونید ( تقریبا وسط صفحه ) شاید من بد متوجه شدم ... ! ، یا شاید هم این یارو هم اشتباه می کنه ...
این فقط برای CPUهای تک هسته ایی صادق هست، و برای CPUهای چند هسته ایی، یا سیستم های دارای چند CPU صدق نمیکنه.
درسته ، این رو نمی دونستم ، ممنون ...
از جناب .M8SPY. هم معذرت می خوام اگر با این پست مسیر بحث رو عوض کردم ...
...
vcldeveloper
یک شنبه 05 اردیبهشت 1389, 18:04 عصر
مطمئنید ؟! ، ولی به نظرم اینطور نیست و Thread اصلی متوقف میشه ، الآن کمی توی گوگل گشتم و این صفحه (http://www.delphicorner.f9.co.uk/articles/db1.htm) رو پیدا کردم ، توضیحاتش در مورد Synchronize رو بخونید ( تقریبا وسط صفحه ) شاید من بد متوجه شدم ... ! ، یا شاید هم این یارو هم اشتباه می کنه ...
اون مقاله که لینکش را ارائه کردید، در اینکه میگه Thread شما بخشی از Thread اصلی میشه، اشتباه میگه. اینکه صحبت از Suspend شدن کرده، منظورش Thread نیست، بلکه عملیاتی هست که در آن Thread در حال انجام بود. در واقع اشکال اون مقاله اینه که مفوهم Thread رو با مفهوم عملیاتی که در یک Thread در حال انجام هست، مخلوط کرده!
ببینید، یک Thread رو مثل یک لوله آب در نظر بگیرید، و کد شما که در Thread اجرا میشه، رو هم آب در نظر بگیرید. وقتی Synchronize اجرای میشه، Thread فراخوان Synchronize بخشی از Thread اصلی نمیشه، یعنی این دو لوله آب با هم ترکیب نمیشند، بلکه، لوله آب فرعی جلوش گرفته میشه، و آب جاری به لوله آب اصلی منتقل میشه، و از طریق لوله اصلی جریان پیدا میکنه. زمانی که اجرای Synchronize پایان یافت، مجددا مسیر فرعی باز میشه.
برای آزمایش این موضوع، می تونید در کد یک Thread متد Synchronize را فراخوانی کنید، و در داخل کدی که Synchronize باید اجرا کنه، یک توقف (مثلا با استفاده از ShowMessage) ایجاد کنید. می بینید که تا زمانی که پیام ShowMessage شما روی صفحه قرار داره، کد بعد از Synchronize در داخل Thread فرعی شما اجرا نمیشه. چون Thread فرعی شما تا پایان اجرای Synchronize متوقف شده.
اون چیزی که در اون مقاله درباره Suspend گفته شده، این هست:
your thread becomes a part of the main thread of the program, and in the process, suspends the operation of the main thread.
بخش اولش رو توضیح دادم (درباره اینکه Thread شما بخشی از Thread اصلی میشه). اما در بخش دوم منظورش اینه که وقتی Syncrhonize اجرا میشه، Thread اصلی عملیاتی که به آن مشغول بود رو ول میکنه،و به Synchronize می پردازه؛ یعنی همچنان Thread اصلی هست که داره کد رو اجرا میکنه. به عبارت ساده تر، همچنان کد Syncrhonize داره از داخل لوله آب اصلی جریان پیدا میکنه. پس Thread اصلی متوقف نشده، بلکه Thread اصلی سرگرم اجرای کدیی که Synchronize بهش تحویل داده شده، میشه. مثل اینکه یکی داره کاری رو انجام میده، بهش بگیم فعلا اون کار رو ولش کن، بیا اول این کار من رو انجام بده، بعدا به اون کارت برس. همچنان همون طرف داره کارها رو انجام میده.
نکته دیگه ایی که اون جمله بهش اشاره میکنه، برمیگرده به کارکرد تکنیک های Synchronization، یعنی دسترسی متوالی (یا سریالی) به منابع به اشتراک گذاشته شده بین Threadها؛ یعنی زمانی که Thread اصلی در حال انجام درخواست Synchronize یکی از Threadهای فرعی هست، اگر یک Thread فرعی دیگه هم درخواست Synchronize ارسال کنه، Thread اصلی نمیتونه همزمان به آن هم پاسخ بده، بلکه Thread فرعی دوم باید منتظر بمونه تا اجرای Synchronize برای Thread فرعی اول تمام بشه، بعدا Thread اصلی به اجرای Synchronize مربوط به Thread فرعی دوم می پردازه.
مقابل متد Synchronize در کلاس TThread متد Queue قرار داره. متد Queue میتونه کدی رو برای Thread اصلی یا Threadهای دیگه ارسال کنه، تا آن کد را اجرا کنند، ولی منتظر اجرای آن کد توسط Thread اصلی یا Threadدیگه نمیشه، بلکه پیامی در صف پیام های اون Thread درج میکنه، که باید این کد اجرا بشه. در این حالت، Threadایی که Queue را فراخوانی کرده، بلافاصله به کار خودش ادامه میده، و منتظر نمیمونه. Threadایی هم که پیام را دریافت کرده، بلافاصله به پیام رسیدگی نمیکنه، بلکه پیام های رسیده را یکی یکی پردازش میکنه، هر وقت نوبت به این پیام رسید، این پیام را هم پردازش میکنه، و کد مربوطه رو اجرا میکنه. در این حالت کد اجرا میشه، ولی معلوم نیست که کی اجرا بشه.
Aftab.R
چهارشنبه 01 آبان 1392, 12:11 عصر
اطلاعات مفیدی بود.
صد دفعه از رو هر پستی خوندم تا یکم واسم تفهیم شد.
اما متاسفانه هنوز نمی تونم کنترلی که روی فرمم دارم رو رفرش کنم.
مثالی که زدید رو هم چندین بار تست کردم و بالا پایین کردم ولی باز نمی تونم تو برنامه م بیارمش.
آخه شما مقدار یه کامپوننت داخلی خود ترد رو عوض کردید و بعد ست کردید تو کامپوننت های فرم.
در حالی که من می خوام کامپوننت فرمم رفرش بشه!!!!! نمی دونم چی کارش کنم؟
Mask
چهارشنبه 01 آبان 1392, 12:51 عصر
متد Synchronize دقیقا برای شما دستورات رو در مین ترد انجام میده. حالا چه رفرش باشه و چه کار دیگه.
نمونه کدتون رو اگه مشکل دارید اینجا قرار بدید.
بهروز عباسی
چهارشنبه 01 آبان 1392, 20:00 عصر
برای درک هرچه بهتر مسائل مربوط به Thread ها پیشنهاد میکنم کپچرهای 7و 8 از کتاب Windows System Programming(4th.Edition) (http://www.amazon.com/Windows-Programming-Addison-Wesley-Microsoft-Technology/dp/0321657748)رو بخونید.:چشمک:
(http://www.amazon.com/Windows-Programming-Addison-Wesley-Microsoft-Technology/dp/0321657748)
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.