PDA

View Full Version : سوال: ايرادات اين thread چيه؟



SayeyeZohor
دوشنبه 19 تیر 1391, 20:21 عصر
unit Uthread;

interface

uses
Registry, Windows, Dialogs,
Math, Classes, SysUtils, ComCtrls, ExtCtrls,
Forms;

type
TTestThread = class(TThread)
private
FInterval: Integer;
procedure UpdateProgressBar;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean);
destructor Destroy; override;
PROCEDURE RefreshTimerTime(Sender: TObject);
PROCEDURE TUserUpdateTimer(Sender: TObject);
end;

var
RefreshTimer, TUserUpdate: TTimer;

implementation

uses MainUnit, TLaki2Unit, ToolsUnit;

PROCEDURE TimersDisable;
BEGIN
IF TFMainTerminate THEN
BEGIN
IF Assigned(RefreshTimer) THEN
BEGIN
RefreshTimer.Enabled := False;
RefreshTimer.Free;
END;
IF Assigned(TUserUpdate) THEN
BEGIN
TUserUpdate.Enabled := False;
TUserUpdate.Free;
END;
END;
END;

PROCEDURE TTestThread.RefreshTimerTime(Sender: TObject);
BEGIN
//IF NOT AccessTina THEN Exit;
IF (NOT AccessTina) OR (TFMainTerminate) OR (CloseLogin) THEN
BEGIN
IF TFMainTerminate THEN TimersDisable;
Exit;
END;

//-- NEW NIKOEI 1391-01-12 --
IF (NOT Laki2Tools.ProcessExists(ModuleRun)) AND (Trim(ModuleRun) <> '') THEN
BEGIN
FMain.PB1.Hide;
FMain.EnableComponent;
ModuleRun := '';
END;
//-- NEW NIKOEI 1391-01-12 --

FMain.RefreshModules;
Screen.MenuFont.Name := 'Tahoma';

IF FMain.AdvNavBar1.Collapsed THEN FMain.AdvSplitter1.Visible := False ELSE FMain.AdvSplitter1.Visible := True;

//-- در صورتي كه براي دومين بار تينا اجرا شد --
Root := HKEY_CURRENT_USER;
Key := 'Software\Microsoft\Windows\CurrentVersion';
NameValue := 'TinaRun2';
IF Laki2Tools.ValueExist(Root, Key, NameValue) THEN
BEGIN
Laki2Tools.DeleteValuee(Root, Key, NameValue);
FMain.Show_HideTina(True);//-- جهت نمايش/مخفي كردن تينا --
END;
END;
PROCEDURE TTestThread.TUserUpdateTimer(Sender: TObject);
BEGIN
IF (NOT AccessTina) OR (TFMainTerminate) OR (CloseLogin) THEN
BEGIN
IF TFMainTerminate THEN TimersDisable;
Exit;
END;

Tools.ExecSql('UPDATE Users SET IsLogin = 1, UDate = '+QuotedStr(Tools.FarsiToday)+', UTime = '+QuotedStr(Laki2Tools.NowTimeNew)+' Where UId = '+UserID)
END;



{ TTestThread } //thread سازنده ...
constructor TTestThread.Create(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);

//IF NOT AccessTina THEN Exit;
IF (NOT FMain.Showing) OR (NOT AccessTina) OR (TFMainTerminate) OR (CloseLogin) THEN Exit;

RefreshTimer := TTimer.Create(nil);
WITH RefreshTimer DO
BEGIN
Interval := 500;
OnTimer := RefreshTimerTime;
Enabled := True;
END;

TUserUpdate := TTimer.Create(nil);
WITH TUserUpdate DO
BEGIN
Interval := 120000;
OnTimer := TUserUpdateTimer;
Enabled := True;
END;

FreeOnTerminate := True;
end;

destructor TTestThread.Destroy; // Do Something destroy ...
begin
inherited;
end;
procedure TTestThread.UpdateProgressBar;
begin
//
end;
procedure TTestThread.Execute;
begin
//FMain.ShowMsg('شروع كار');
Exit;
Synchronize(UpdateProgressBar);
end;

end.


:قلب:

SayeyeZohor
سه شنبه 20 تیر 1391, 20:55 عصر
كسي نيست بگه ايراد اين ترد رو؟:گریه:

بهروز عباسی
سه شنبه 20 تیر 1391, 21:11 عصر
كسي نيست بگه ايراد اين ترد رو؟:گریه:
این یونیت مال برنامه خاصیه؟
الان توی دلفی نگاش کردم به این یونیت ها هم احتیاج داره uses MainUnit, TLaki2Unit, ToolsUnit, Unit1;
اگه ممکنه بقیه کد هم بذار.

موفق باشید

SayeyeZohor
چهارشنبه 21 تیر 1391, 00:16 صبح
عزيز ميخواستم بدونم استايل نوشتن thread ام درسته يا نه؟:خجالت:

Felony
چهارشنبه 21 تیر 1391, 05:48 صبح
توقع نداری که یکی بشینه و 130 خط کد شما رو بررسی کنه و بگه اشکال داره یا نداره ؟ میتونید کدهای مطمئنی که افراد با تجربه تو همین سایت یا سایت های خارجی قرار دادن رو مطالعه کنید و کدتون رو با اونها مقایسه کنید و در نهایت در مورد قسمت خاصی از کدتون سوال بپرسید و اون رو به بحث بزارید نه کل کدها رو یکجا بزارید اینجا و بگید ساختارش درست هست یا نه .

اینطوری خیلی ها بی تفاوت از کنار سوالتون میگذرن چون وقتش رو ندارن ، به شخصه 2 روز پیش که تاپیک رو زدید سوالتون رو دیدم ولی وقتی دیدم کدها زیاده و وقتم محدود بیخیال پاسخ دادن شدم ، در ضمن این نوع کدها رو نمیشه اینطوری بررسی کرد و بهتره سورس قرار بگیره ، الان تو اون کد کلی متغییر و ارجاع گنگ وجود داره .

SayeyeZohor
چهارشنبه 21 تیر 1391, 08:53 صبح
unit Uthread;

interface

uses
Registry, Windows, Dialogs,
Math, Classes, SysUtils, ComCtrls, ExtCtrls,
Forms;

type
TTestThread = class(TThread)
private
FInterval: Integer;
procedure UpdateProgressBar;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean);
destructor Destroy; override;
PROCEDURE RefreshTimerTime(Sender: TObject);
PROCEDURE TUserUpdateTimer(Sender: TObject);
end;

var
RefreshTimer, TUserUpdate: TTimer;

implementation

uses MainUnit, TLaki2Unit, ToolsUnit;

PROCEDURE TimersDisable;
BEGIN
//-- استفاده شده غيرفعال و آزاد بشند Thread در اين قسمت چك شده در صورتي كه پروژه در حال بسته شدنه دو تايمري كه در --
{
IF TFMainTerminate THEN
BEGIN
IF Assigned(RefreshTimer) THEN
BEGIN
RefreshTimer.Enabled := False;
RefreshTimer.Free;
END;
IF Assigned(TUserUpdate) THEN
BEGIN
TUserUpdate.Enabled := False;
TUserUpdate.Free;
END;
END;
}
END;

PROCEDURE TTestThread.RefreshTimerTime(Sender: TObject);
BEGIN
//-- در اين تايمر هم چند تا كار از قبيل آپديت كردن جدول كاربران و ... انجام مي شه --
{
//IF NOT AccessTina THEN Exit;
IF (NOT AccessTina) OR (TFMainTerminate) OR (CloseLogin) THEN
BEGIN
IF TFMainTerminate THEN TimersDisable;
Exit;
END;

//-- NEW NIKOEI 1391-01-12 --
IF (NOT Laki2Tools.ProcessExists(ModuleRun)) AND (Trim(ModuleRun) <> '') THEN
BEGIN
FMain.PB1.Hide;
FMain.EnableComponent;
ModuleRun := '';
END;
//-- NEW NIKOEI 1391-01-12 --

FMain.RefreshModules;
Screen.MenuFont.Name := 'Tahoma';

IF FMain.AdvNavBar1.Collapsed THEN FMain.AdvSplitter1.Visible := False ELSE FMain.AdvSplitter1.Visible := True;

//-- در صورتي كه براي دومين بار تينا اجرا شد --
Root := HKEY_CURRENT_USER;
Key := 'Software\Microsoft\Windows\CurrentVersion';
NameValue := 'TinaRun2';
IF Laki2Tools.ValueExist(Root, Key, NameValue) THEN
BEGIN
Laki2Tools.DeleteValuee(Root, Key, NameValue);
FMain.Show_HideTina(True);//-- جهت نمايش/مخفي كردن تينا --
END;
END;
PROCEDURE TTestThread.TUserUpdateTimer(Sender: TObject);
BEGIN
IF (NOT AccessTina) OR (TFMainTerminate) OR (CloseLogin) THEN
BEGIN
IF TFMainTerminate THEN TimersDisable;
Exit;
END;

Tools.ExecSql('UPDATE Users SET IsLogin = 1, UDate = '+QuotedStr(Tools.FarsiToday)+', UTime = '+QuotedStr(Laki2Tools.NowTimeNew)+' Where UId = '+UserID)
}
END;



{ TTestThread } //thread سازنده ...
constructor TTestThread.Create(CreateSuspended: Boolean);
begin
//-- در اين قسمت تايمر هام به صورت دايناميك ساخته و فعال مي شند --

{
inherited Create(CreateSuspended);

//IF NOT AccessTina THEN Exit;
IF (NOT FMain.Showing) OR (NOT AccessTina) OR (TFMainTerminate) OR (CloseLogin) THEN Exit;

RefreshTimer := TTimer.Create(nil);
WITH RefreshTimer DO
BEGIN
Interval := 500;
OnTimer := RefreshTimerTime;
Enabled := True;
END;

TUserUpdate := TTimer.Create(nil);
WITH TUserUpdate DO
BEGIN
Interval := 120000;
OnTimer := TUserUpdateTimer;
Enabled := True;
END;

FreeOnTerminate := True;
}
end;

destructor TTestThread.Destroy; // Do Something destroy ...
begin
inherited;
end;
procedure TTestThread.UpdateProgressBar;
begin
//
end;
procedure TTestThread.Execute;
begin
//-- در اين قسمت هم كدي ننوشتم --
{
//FMain.ShowMsg('شروع كار');
Exit;
Synchronize(UpdateProgressBar);
}
end;

end.


سوال اصلي من اينه كه آيا اين Thread من از نظر اصولي درسته يا نه؟
:خجالت:

Saeed_m_Farid
چهارشنبه 21 تیر 1391, 13:36 عصر
مثلآً این کد شما با قبلی چه تفاوتی کرد! فقط کامنت کردین؟
من مواردی که به نظرم رسید رو میگم:


بزرگترین مشکل یونیت شما اینه که با درست کردن یک شیء از این Thread و Start اون، برنامه کلاً به فنا میره :( در بندهای بعدی برخی دلایل‌اش رو میگم ولی کلاً Thread در این کد، یک چیز زائد هست که ازش هیچ استفاده‌ای نشده! تمام کارها در OnTimer تایمرها بصورت کاملاً unsafe انجام می‌گیرن؛ قبل استفاده از تایمر در یک برنامه Multi-Thread شما باید با نمونه‌ای از اونها کار کرده باشید، تا سرنخ بیاد دست‌تون، هزاران Tutorial براش هست و اگه کسی هم مشکل داشته باشه (مثل این (http://stackoverflow.com/questions/11244848/delphi-timer-inside-thread-generates-av))، میشه فهمید که قبلاً چند تا مثال ساده کار کرده و الان برای استفاده از تایمر در Thread به یه مشکلی خورده...
استفاده مستقیم از اشیاء خارج از Thread و مخصوصاً عناصر وابسته به Thread اصلی برنامه! (در مورد Synchronize که هزاران بار بحث شده! برای سایر عناصر که نیاز به Invoking ندارن هم هیچوقت هاردکد نکنید، بهتره بعنوان پارامتر -مثلاً property در کلاس Thread- ازشون استفاده کنید)
منابعی (تایمرها) که از سیستم می‌گیرید رو رها نمی‌کنید، Destroy رو پس واسه چی override کردین؟!
"در اين قسمت هم كدي ننوشتم": پس Thread رو واسه چی درست کردین؟ Constructor فقط برای مقداردهی اولیه است نه همه کارها! اونهم اینقدر کارهای خطرناک!!!
Directiveهای کلاس کاملاً بی‌معنی هستند! تنها RefreshTimerTime و TUserUpdateTimer بعنوان public تعریف شدند که کاربرد بدردبخوری برای شیء ساخته شده از این کلاس (یا وارث) ندارن! protected هم که خالیه! یعنی کلاس شما کاملاً خودسر و غیرقابل استفاده از دید شیء و کلاس ارث برنده و ... میشه.
برای تایمرها (خودشون، Enabled ،Interval)، تینا، مینا و ... هیچ property ای تعریف نشده! شما همه چیز رو بصورت هاردکد قرار دادین و فردا-روزی اگه نام فرم، عناصر روش، نام جدول، فیلدها، کلید رجیستری و ... عوض بشه، یونیت شما کاملاً بی‌مصرف میشه.
با اینکه معلوم نیست TFMainTerminate چی هست! و شما هم با کوشش وافری سعی در چک کردن اون دارید؛ با فرض اینکه منظور Termination فرم اصلی باشه، تا وقتی فرم اصلی Terminate نشه استفاده کننده از یونیت شما به هیچ وجه نمی‌تونه تایمرها رو متوقف کنه! دلیل این‌کار هرچی هم باشه، شما باید یه راه فرار برای خودتون بذارید تا در صورت بروز اشکال، مجبور به End task کل برنامه نشید!‌ (ضمناً لازم نیست صدبار چک کنید، یکبار قبل یا بعد از TimersDisable کافی بود)
هیچ روند کنترل Exceptionای در کد شما رویت نشد!
اول نام متغیر، شیء و ... هیچوقت T نمی‌دارن (TUserUpdate و TLaki2Unit و ...) اون حرف برای سرآغاز یک نوع جدید هست...
برای پیاده سازی این Thread اصلاً احتیاجی به تایمر نیست، چون شما نمی‌دونید چه‌طوری توسط VCL پیاده‌سازی شده! شما بهتره از WaitForSingleObject (http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032%28v=vs.85%29.aspx) برای انتظار نتیجه و ... استفاده کنید.
آدم از اینکه هدف / نیّت شما رو کلاً از ایجاد چنین یونیتی نمی‌فهمه دچار سردرد مزمن میشه :(

این گوشه‌ای از نظرات من بود.

موفق باشید./

N30TheM4TRIX
چهارشنبه 21 تیر 1391, 22:13 عصر
سلام ترد من امن هست یا نه؟


unit Unit2;

interface

uses
System.Classes, Winapi.Windows, System.SysUtils,Vcl.StdCtrls;

type
TTest = class(TThread)
private
FEvent: Integer;
FResult: Integer;
procedure InitThread;
public
constructor Create();
destructor Destroy; override;
procedure StopThread;
protected
procedure ResultEX;
procedure Execute; override;
end;

implementation

{ TTest }

uses Unit1;

constructor TTest.Create();
begin
inherited Create(true);
FResult := 0;
end;

destructor TTest.Destroy;
begin
CloseHandle(FEvent);
inherited;
end;

procedure TTest.Execute;
begin
InitThread;
while not Terminated do
begin
if WaitForSingleObject(FEvent, INFINITE) = WAIT_OBJECT_0 then
begin
inc(FResult, 10);
ResultEX;
resetevent(FEvent);
end; { Comment }
end;
end;

procedure TTest.InitThread;
begin
FEvent := CreateEvent(nil, true, false, 'test');
setEvent(FEvent);
end;

procedure TTest.ResultEX;
begin
form1.caption:=IntToStr(FResult) ;
end;

procedure TTest.StopThread;
begin
Terminate;
setEvent(FEvent);
WaitFor;
end;

end.

Saeed_m_Farid
پنج شنبه 22 تیر 1391, 09:30 صبح
سلام ترد من امن هست یا نه؟...
در مورد امن بودن، نمیشه به همین راحتی نظر داد، چون نحوه استفاده / توسعه thread شما می‌تونه رو نتیجه کار تاثیر بذاره! به‌نظرم برای اینکار بهتره از ReportMemoryLeaksOnShutdown (http://delphi.about.com/od/adptips2006/qt/memory_leak.htm) استفاده کنید، مثلاً قبل از Application.Initialize این کد رو بذارید: ReportMemoryLeaksOnShutdown := DebugHook <> 0;
ولی چند تا نکته درمورد Thread ‌شما:


بهتره مثل Thread دوستمون SayeyeZohor (http://barnamenevis.org/member.php?95079-SayeyeZohor) شما هم CreateSuspended رو به عنوان پارامتر به سازنده بدین، اگه مایلید که اتوماتیک Thread بصورت Suspend کار کنه، می‌تونید پیش‌فرص بهش بدین:constructor Create(CreateSuspended: Boolean = True);
همانطورکه می‌دونید باید از Synchronize برای تغییر caption (و هر شیء UIای که در Thread اصلی برنامه قرار داره) در تابع ResultEX استفاده می‌کردین که نکردین!
FEvent رو از نوع THandle تعریف کنید.
استفاده از INFINITE در WaitForSingleObject خطرناک هست، من این کد رو تست نکردم ولی فکر کنم می‌افته تو حلقه بی‌نهایت، چون در StopThread هم WaitFor گذاشتین؛ بهتره یه Timeout برای WaitForSingleObject قرار بدین: WaitForSingleObject(FEvent, High(SmallInt)) = WAIT_TIMEOUT
چون احتمال فراموش شدن خالی کردن منابع گرفته شده از سیستم هست، بهتره از: FreeOnTerminate := True; استفاده کنید، مگر اینکه یه سیگنال بفرستید به ویندوز پروسیجر فرم اصلی (یا یه جای دیگه که PostMessage رو بتونه هندل کنه) و اونجا بهش بگید که منابع رو FreeAndNil کنه، که در مواقع خاص تری لازم میشه که دست شما تو Thread بسته هست و ...
در Destroy یادتون رفته SetEvent کنید.
شما هم استفاده از try ... except رو فراموش کردید.
بهتره در while بسته شدل application‌ رو هم لحاظ کنید: Application.Terminated
دیگه چیزی به ذهنم نرسید :دی

بهروز عباسی
پنج شنبه 22 تیر 1391, 10:03 صبح
درود به همه

همانطورکه می‌دونید باید از Synchronize برای تغییر caption (و هر شیء UIای که در Thread اصلی برنامه قرار داره) در تابع ResultEX استفاده می‌کردین که نکردین!
یعنی برای چنین کاری حتما باید از Synchronize استفاده کنیم (مشکل من).

چون این تابع سهولت رو فدای کارایی می کنه و در برنامه های بزرگ فکر کنم افت کارایی و سرعت رو همراه داشته باشه؟ اینطور نیست؟

Felony
پنج شنبه 22 تیر 1391, 10:34 صبح
چون این تابع سهولت رو فدای کارایی می کنه و در برنامه های بزرگ فکر کنم افت کارایی و سرعت رو همراه داشته باشه؟ اینطور نیست؟
تغییر UI به صورت مستقیم از داخل Thread ها خلاف قوانین برنامه نویسی Multi Threading هست ؛ ساده ترین راه کار استفاده از Synchronize هست که کد شما رو در Context ترد اصلی برنامه ( Main Thread ) اجرا میکنه ، پس در زمان اجرای کدهای پاس داده شده به Synchronize روال عادی اجرای کدهای Main Thread متوقف میشه و کدهای پاس داده شده به Synchronize اجرا میشه و پس از پایان اجرای این کدها در Context ترد اصلی برنامه ، اجرای روال عادی کدهای Main Thread ادامه پیدا میکنه ، پس عملا در این زمان اگر کدهای سنگینی اجرای کنید UI برنامه فریز میشه ، چون وظیفه به روز رسانی رابطه کاربری برنامه با Main Thread هست و Main Thread هم که مشغول اجرای کدهای پاس داده شده توسط Synchronize .

راه های دیگه ای مثل مبادله پیغام ها و ... وجود داره که مشکل فریز شدن UI رو ندارن ، هر کدوم از این سناریو ها و راهکارها رو بر طبق نیازهاتون در پروژه باید انتخاب کنید و هر کدوم مزایا و معایبی دارن ، در مورد ارسال پیغام ها در ترد میتونید تو بخش نمونه سورس ها بگردید ، قبلا نمونه ای جهت کپی فایل ها با ترد قرار داده بودم که از ارسال پیغام برای به روز رسانی رابط کاربری استفاده میکرد .

Saeed_m_Farid
پنج شنبه 22 تیر 1391, 10:42 صبح
چون این تابع سهولت رو فدای کارایی می کنه و در برنامه های بزرگ فکر کنم افت کارایی و سرعت رو همراه داشته باشه؟ اینطور نیست؟
بله، دقیقاً اینطوریه (بحث در اینمورد (http://stackoverflow.com/questions/1806339/is-it-better-to-use-tthreads-synchronize-or-use-window-messages-for-ipc-betwe)) برای همینه که اساتید اینجا، همیشه OmniThreadLibrary (http://otl.17slon.com/) رو پیشنهاد می‌کنن؛ با استفاده از این‌ کتابخانه، پیچیدگی‌ها و اشتباهات سهوی برنامه‌های Multi-thread به میزان زیادی کاهش پیدا می‌کنه و همزمان سادگی بیشتری هم فراهم میشه و ...
ولی در صورت اصرار به استفاده مستقیم از TThread بهتره از PostMessage و روال‌های ویندوز پروسیجری استفاده کنید و میدونم که بسیار در موردشون صحبت شده و چون من زیاد اینجا فعالیت نداشتم، با اجازه اساتید پست‌های عهد بوقی که یادم بود رو برای مراجعه میذارم (اینجا (http://barnamenevis.org/showthread.php?160611&p=727311&viewfull=1#post727311) و اینجا (http://barnamenevis.org/showthread.php?223962&p=995486&viewfull=1#post995486) و بقیه هم یادم نیست!)

بهروز عباسی
پنج شنبه 22 تیر 1391, 11:59 صبح
خیلی ممنون از اساتید گرامی به خاطر پاسخ های خوبشون




همیشه OmniThreadLibrary (http://otl.17slon.com/) رو پیشنهاد می‌کنن//حقیقتی تلخ وجود داره اونم این که زبانم زیاد خوب نیست//
و اگه ممکنه در این باره کمی توضیح بدید:
مگه این OmniThreadLibrary (http://otl.17slon.com/) از توابع API ویندوز برای ایجاد و مدیریت Thread ها استفاده نمیکنه؟ (در این صورت با TThread دلفی یکی هستش)!
یا اینکه مدیریت بهتری نسبت به پیشفرض های خود دلفی بر روی Thread ها داره؟؟

Saeed_m_Farid
پنج شنبه 22 تیر 1391, 12:56 عصر
مگه این OmniThreadLibrary (http://otl.17slon.com/) از توابع API ویندوز برای ایجاد و مدیریت Thread ها استفاده نمیکنه؟ (در این صورت با TThread دلفی یکی هستش)!
یا اینکه مدیریت بهتری نسبت به پیشفرض های خود دلفی بر روی Thread ها داره؟؟
بله، حتماً‌ که "مدیریت بهتری نسبت به پیشفرض های خود دلفی بر روی Thread ها داره" : اولی و مهمترینش، استفاده از Thread pool هست؛ دقیقاً یادم نیست ولی 2-3 سال پیش جناب کشاورز بنده رو با این کتابخونه آشنا کردن و از اون‌موقع به بعد بالشخصه که کاملاً از درگیری با لایه‌های پائین معاف شدم! یعنی پیاده‌سازی‌های نامطمئن درگیر MemoryLeak های عجیب و غریب نمی‌شم (در حقیقت هرجند جزئی ولی همیشه این گرفتن و رها نکردن منابع، برای یه برنامه سیستمی دغدغه خواهد بود، چون با افزایش مدت زیربار بودن سیستم؛ قطره، قطره وانگهی دریا می‌گردد و پدرصابش رو درمی‌آورد!) فرض کنید برنامه‌هایی که قرار باشه 100 تا Concurrent thread داشته باشند و شما از Thread-pool استفاده نکنید، این معادل است با فاجعه!
یه پست خوب (http://barnamenevis.org/showthread.php?313501&p=1386174&viewfull=1#post1386174)(همین فروم!) در این زمینه ببینید، ولی من جسارت نمی‌کنم در مورد این کتابخونه نظر بدم، چون اولاً خودم از اساتید همین فروم باهاش آشنا شدم و ازطرف دیگه، متاسفانه دیگه خیلی کم native کار می‌کنم‌ (فعلاً درگیر چیزای دیگه شدیم:( ) ...
ضمناً سعی کنید که این حقیقت تلخ رو عوض کنید و از سرچشمه آب بگیرید!
_____________


در مورد Synchronize در OTL (http://www.thedelphigeek.com/2011/03/synchronize-comes-to-omnithreadlibrary.html)
یکی از فوق‌العاده‌ترین کاربردها: OmniThreadLibrary internals - OtlComm (http://www.thedelphigeek.com/2008/07/omnithreadlibrary-internals-otlcomm.html) یه چیزی مثل کانال‌های WCF دات نت(سطوح IChannelListener (http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.ichannellistener.aspx ) و ChannelFactory (http://msdn.microsoft.com/en-us/library/system.servicemodel.channelfactory.aspx))، ولی در کاربردهای سیستمی ...