# Native Code > برنامه نویسی در Delphi > مباحث عمومی دلفی و پاسکال >  آموزش قدم به قدم thread

## Mask

با سلام به همه دوستان.
بنده تا حالا با thread ها کار نکردم . و تا حالا چنتا برنامه حسابداری فقط نوشتم .
در مورد سوالم در لینک زیر
https://barnamenevis.org/showth...875#post796875
به نظرم با صحبت دوستام بهترین گزینه thread هست.
با جستجو در سایت کلی مطلب پیدا کردم که آقای کشاورز و دوستان توضیح داده بودند.اما واقعا هیچی متوجه نشدم چون تخصصی بود.
حالا از دوستانی که اطلاعات دارند زحمت بکشند و از معرفی thread و این چه ابزار یا کلاس یا چه شیئ هست شروع و به چه کاری میاد و یواش یواش یه نمونه ساده استفاده از thread رو اینجا بزارند که خط به خط تحلیلش کنیم تا این مطلب رو همگی یاد بگیریم.
تا بتونیم از thread ها کامل و بهینه استفاده کنیم.
اول هم من شروع می کنم اطلاعاتی رو کسب کردم. کامل متوجه نشدم چی میگه اما میزارم اینجا دوستا بیشتر بازش کنند.




> *مقدمه :*
> 
> Thread ها ابزاری مفید هستند که به کاربر اجازه می دهند تا اعمالی را به صورت موازی (Parallel) و همزمان انجام دهد. با استفاده از Thread ها، از امکانات MultiTasking در یک برنامه استفاده می کنید. در ضمن می توانید یک قسمت از برنامه را متوقف و یا به جریان بیندازید. در استفاده از Threadها بسیار مراقب باشید چون منابع شما محدود هستند.
> Threadها هنگامی که باید منتظر پاسخ بخشی دیگر از برنامه باشید، بسیار به کار می آیند و شما می توانید در حالی که بخشی از برنامه متوقف است و منتظر پاسخ است بقیه قسمت ها را پیش ببرید که سرعت برنامه های شما را به طرز قابل ملاحظه ای افزایش می دهد..





> thread یا در اصطلاح "نخ" پراسس ها کوچکی هستند که هر کدام تنها یک هدف رو انجام می دن و در نهایت پس از پایان یافتن اجرای مجموعه thread ها یک برنامه یا یک پراسس اصلی پایان پیدا می کنه. از thread برای انجام کارهای موازی همزمان استفاده میشه. اکثر برنامه هایی که ما می نویسیم فقط یک thread دارند که همون پراسس اصلی ماست و با پایان یافتن اون، برنامه هم به پایان میرسه.





> Thread چيست؟
> هر Thread از یکسری فرمان های پشت سر هم ساخته می شود. این فرمان ها شامل شمارنده (Counter)، فراخوانی و بازگشت پشته (Call/Return Stack) و داده های خود Thread می شود. 
> هر Task از یک یا چند Thread تشکیل می گردد.





> ببينيد ، وقتي شما يک برنامه يا ... رو اجرا مي کنيد ، ويندوز يک رشته يا همون Thread رو بهش اختصاص مي ده ، يعني هر برنامه اجرا شده يک Thread داره ...
> نکته جالب اينه که در ويندوز هرگز دو Thread باهم و همزمان اجرا نمي شن !! ...
> وقتي برنامه شما اقدام به انجام کاري ( يا کدي که شما نوشتيد ) مي کنه ، اون کار رو توي همون Thread اي که خود برنامه اصلي شما داره ، اجرا مي کنه ، خوب اين مسلما روي بقيه اعضاء برنامه هم تاثير مي زاره و اگر کدي که برنامه شما داره اجراش مي کنه ، حافظه ي زيادي لازم داشته باشه ، روي Interface برنامه اصلي تاثير مي زاره و برخي مواقع باعث کند شدن برنامه يا هنگ کردن برنامه براي مدت کوتاه يا زياد ميشه ...
> نمونه اين کندي رو مي شه در مواقع دريافت اطلاعات در برنامه هاي تحت شبکه ديد ، که اگه به خوبي از Thread ها استفاده بشه ، اين مشکل حل ميشه ...


در لینک زیر هم آقای کشاورز توضیح دادند
http://www.barnamenevis.org/sh...ad.php?t=26406

----------


## Mahmood_M

با سلام ...
مبحث Thread ها گسترده تر از اون چیزیه که بشه کلش رو در حتی چند مقاله بیان کرد ...
در سایت چندین بار در مورد Thread ها صحبت شده ، به سئوالاتی پاسخ داده شده و مقالاتی هم در سایت قرار گرفته ، اگه قرار باشه ، دوباره از اول توضیح داده بشه ، یک کار دوباره خواهد بود ...
پیشنهاد میکنم ابتدا مقالات و تاپیکهای مربوط رو بخونید و هر جایی که به مشکل برخوردید سئوالتون رو مطرح کنید تا براتون روشن بشه ...
برخی از تاپیکهای مفید در این زمینه :
مقاله : https://barnamenevis.org/showthread.php?t=79463
تاپیک مفید : https://barnamenevis.org/showthread.php?t=155998
تاپیک مفید : https://barnamenevis.org/showthread.php?t=167626
...
بهتر از همه این تاپیکها خود راهنمای دلفی هست که می تونه کمکتون کنه ...

بهتره مطالب بالا رو مطالعه کنید و هرجا که مشکل داشتید بپرسید ...

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

----------


## FiACKER

دوسته عزيز كجاي مطالب بالا مشكل داريد ؟

كجاشو متوجه نشديد ؟

----------


## vcldeveloper

> اصلا من با  Thread مشکل دارم.
> اولا دقیقا به چه درد می خوره. مثلا یه برنامه که با اجرای یه دستور هنگ میکنه Thread چجوری از هنگ سیستمو در میاره.


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

الان بحث هایی مثل اینکه کلاس TThread در دلفی این هست، یا فلان خصوصیت این کلاس فلان کار را می کند، و چیزهایی از قبیل این، کمک خاصی به شما نمیکنه، یا باعث میشه بیشتر سردرگم بشید، یا باعث میشه که فکر کنید فهمیدن multi-threading یعنی فهمیدن کار کلاس TThread و خصوصیات و متد های آن! نتیجه اش هم این میشه که با تکیه بر اطلاعات ناقص، برنامه می نویسید، و به مشکل بر می خورید.

----------


## Mask

به نقل از  http://www.srco.ir/WhyHow/Contents/WhatIsOS.htm



> *سيستم عامل*  سيستم عامل بدون شک مهمترين  نرم افزار در کامپيوتر است . پس از روشن کردن کامپيوتر اولين نرم افزاری که مشاهده می گردد سيستم عامل بوده و آخرين نرم افزاری که  قبل از خاموش کردن کامپيوتر مشاهده خواهد شد، نيز سيستم عامل است . سيستم عامل نرم افزاری است که امکان اجرای تمامی برنامه های کامپيوتری را فراهم می آورد. سيستم عامل با سازماندهی ، مديريت و کنترل منابع  سخت افزاری امکان استفاده بهينه و هدفمند آنها را فراهم می آورد. سيتم عامل فلسفه بودن سخت افزار را بدرستی تفسير  و در اين راستا امکانات متعدد و ضروری جهت حيات ساير برنامه های کامپيوتری را فراهم می آورد. 
> تمام کامپيوترها از سيستم عامل استفاده نمی نمايند. مثلا"  اجاق های مايکرويو که در آشپزخانه استفاده شده دارای نوع خاصی از کامپيوتر بوده که از سيستم عامل استفاده نمی نمايند. در اين نوع سيستم ها بدليل انجام عمليات محدود و ساده، نيازی به وجود سيستم عامل نخواهد بود. اطلاعات ورودی و خروجی با استفاده از دستگاههائی نظير صفحه کليد و نمايشگرهای LCD ، در اختيار سيستم گذاشته می گردند. ماهيت عمليات انجام شده در يک اجاق گاز مايکروويو بسيار محدود  و مختصر است، بنابراين همواره يک برنامه در تمام حالات و اوقات اجراء خواهد شد. 
> برای سيستم های کامپيوتری که دارای عملکردی بمراتب پيچيده تر از اجاق گاز مايکروويو می باشند، بخدمت گرفتن يک سيستم عامل باعث افزايش کارآئی سيستم و تسهيل در امر پياده سازی برنامه های کامپيوتری می گردد. تمام کامپيوترهای شخصی دارای سيستم عامل می باشند. ويندوز يکی از متداولترين سيستم های عامل است . يونيکس يکی ديگر از سيستم های عامل مهم در اين زمينه است .  صدها نوع سيستم عامل تاکنون با توجه به اهداف متفاوت طراحی و عرضه شده است. سيستم های عامل مختص کامپيوترهای بزرگ، سيستم های روبوتيک، سيستم های کنترلی بلادرنگ ، نمونه هائی در اين زمينه می باشند. 
> سيستم عامل با ساده ترين تحليل و بررسی دو عمليات اساسی را در کامپيوتر انجام می دهد : 
> <LI dir=rtl>مديريت منابع نرم افزاری و سخت افزاری يک سِستم کامپيوتری را برعهده دارد. پردازنده ، حافظه، فضای ذخيره سازی  نمونه هائی از منابع اشاره شده می باشند .روشی پايدار و يکسان برای دستيابی و استفاده  از سخت افزار را بدو ن نياز از جزئيات عملکرد هر يک از سخت افزارهای موجود را برای برنامه های کامپيوتری فراهم می نمايد  *اولين وظيفه* يک سيستم عامل،  مديريت منابع سخت افزاری و نرم افزاری است . برنامه های متفاوت برای دستيابی به منابع سخت افزاری نظير: پردازنده ، حافظه،  دستگاههای ورودی و خروجی، حافطه های جانبی، در رقابتی سخت شرکت خواهند کرد.  سيستم های عامل بعنوان يک مدير عادل و مطمئن زمينه استفاده بهينه از منابع موجود را برای هر يک از برنامه های کامپيوتری فراهم می نمايند. 
> *وظيفه دوم* يک سيستم عامل ارائه يک رابط ( اينترفيس ) يکسان برای ساير برنامه های کامپيوتری است . در اين حالت زمينه استفاده بيش از يک نوع کامپيوتر از سيستم عامل فراهم شده و در صورت بروز تغييرات در سخت افزار سيستم های کامپيوتری نگرانی خاصی از جهت اجرای برنامه وجود نخواهد داشت، چراکه سيستم عامل بعنوان ميانجی بين برنامه های کامپيوتری و سخت افزار ايفای وظيفه کرده و مسئوليت مديريت منابع سخت افزاری به وی سپرده شده است .برنامه نويسان کامپيوتر نيز با استفاده از نقش سيستم عامل بعنوان يک ميانجی براحتی برنامه های خود را طراحی و پياده سازی کرده و در رابطه با اجرای برنامه های نوشته شده بر روی ساير کامپيوترهای مشابه  نگرانی نخواهند داشت . ( حتی اگر ميزان حافظه موجود در دو کامپيوتر مشابه نباشد ) . در صورتی که سخت افزار يک کامپيوتر بهبود و ارتقاء يابد، سيستم عامل اين تضمين را ايجاد خواهد کرد که برنامه ها، در ادامه بدون بروز اشکال قادر به ادامه حيات وسرويس دهی خود باشند. مسئوليت مديريت منابع سخت افزاری برعهده سيتم عامل خواهد بود نه برنامه های کامپيوتری، بنابراين در زمان ارتقای سخت افزار يک کامپيوتر مسئوليت سيتستم عامل در اين راستا اولويت خواهد داشت . ويندوز 98 يکی از بهترين نمونه ها در اين زمينه است . سيستم عامل فوق بر روی سخت افزارهای متعدد توليد شده توسط توليدکنندگان متفاوت اجراء می گردد.  ويندوز 98 قادر به مديريت و استفاده از هزاران نوع چاپگر ديسک و ساير تجهيزات جانبی است . 
> سيستم های عامل را از بعد نوع کامپيوترهائی که قادر به کنترل آنها بوده و نوع برنامه های کاربردی که قادر به حمايت از آنها می باشند به چهار گروه عمده تقسيم می نمايند. 
> <LI dir=rtl>*سيستم عامل بلادرنگ (RTOS)*. از اين نوع سيستم های عامل برای کنترل  ماشين آلات صنعتی ، تجهيزات علمی و سيستم های صنعتی استفاده می گردد. يک سيستم عامل بلادرنگ دارای امکانات محدود در رابطه با بخش رابط کاربر و برنامه های کاربردی مختص کاربران می باشند.  يکی از بخش های مهم اين نوع سيستم های عامل ، مديريت منابع موجود کامپيوتری بگونه ای است که يک عمليات خاص در زمانی که می بايست ، اجراء خواهند شد.  
> <LI dir=rtl>*تک کاربره - تک کاره* . همانگونه که از عنوان اين نوع سيستم های عامل مشخص است، آنها بگونه ای طراحی شده اند که قادر به مديريت کامپيوتر بصورتی باشند که يک کاربر در هر لحظه قادر به انجام يک کار باشد. سيستم عامل Palm OS برای کامپيوترهای PDA نمونه ای مناسب از يک سيستم عامل مدرن تک کاربره و تک کاره است .  
> ...

----------


## vcldeveloper

> آقای کشاورز به نظرتون فقط برای قضیه Thread به نظرتون منطقیه که من کل کتاب سیستم عامل رو بخونم . برای فقط این بحث؟؟؟!!!


اصولا اگر شما یک آشنایی اولیه با یک سیستم عامل و چگونگی کارکرد آن نداشته باشید، برنامه نویسی برای آن سیستم عامل غیر منطقی هست! شما می تونید مباحثی که به درک مفهوم Thread در سیستم عامل کمک میکنه را مطالعه کنید.




> اینا دسگیرم شد اما یه سوال در برنامه ای که 10تا حلقه و if تو در تو داره چطوری برنامم رو Thread بندی کنم.


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

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

----------


## FiACKER

> هر کجا که این کد رو میزارم تو برنامه ارور میده..  این کد رو کجای برنامه باید بزارم.


اگه كمي در مورد كدهايي كه گذاشتيد فكر مي كرديد متوجه مي شديد كه MyThread كلاسي هست كه خودمان ساخته ايم و حالا مي خوايم يه نمونه ازش بسازيم تا استفاده كنيم.
پس بايد يك كلاس كه از TThread مشتق مي شود بسازيد و اسم اون رو هم MyThread بگذاريد. البته اين توضيحه من براي شما اشتباه است و مثله اينكه شما از پايه در مورد كلاس ها و اشيا مشكل داريد.

البته براي ساخت ترد مي تونيد از توابع api هم استفاده كنيد كه مزيت ها و مشكلاتي داره.

----------


## Saeed_m_Farid

> ...یه نمونه برنامه که یه thread کوچولو استفاده شده به عنوان مثال بزارید.
> من از دوستان انتظار دارم بنده رو راهنمایی کنند و از یه جا یواش یواش وارد بحث برنامه نویسی thread(البته یه سری اطلاعات در مورد thread در سیستم عامل کسب کردم) بشیم.
> ... و تا حدودی با توابع و کلاسها کار کردم.


سلام دوست عزیز، 
چون علیرغم راهنمایی های دوستان برای درک مفهوم Multithreading و کاربردهای اون تو برنامه نویسی، باز هم شما اصرار به ارائه مثال دارید و از طرف دیگه تو اینجا تاپیک زدید؛ من یه نمونه فقط برای شروع نحوه استفاده (و نه درک کاربرد thread تو برنامه های کاربردی و ...) براتون میذارم و امیدوارم که وقت داشته باشم که این مبحث رو (با کمک دوستان) ادامه بدم (علیرغم توضیحات مبسوط قبلی اساتید) :

=============================


در این مثال فرض میشه شما حداقل ها رو از کلاس ها (اعضاء، متدها، سازنده و مخرب ها و ...) میدونید، در ضمن به علت سادگی، از کلاس TThread خود دلفی استفاده میشه

3 تا TLabel (برای نمایش درصد پیشرفت) و یک TButton (برای ایجاد Thread) و یک TProgressBar (برای نمایش درصد پیشرفت) و یک TEdit (برای تعیین وقفه زمانی) رو فرم تون قرار بدید : 


اونها رو به صورت زیر رو فرمتون بچبنید :



File->New->Other رو زده و در پنجره New یک Thread Object انتخاب کرده و یک سازنده و مخرب برای کلاس Thread بسازید(در این مثال ما برای مخرب کدی نداریم، ان شا.. در مثال های کاربردی کارایی این متد بررسی میشه ...)، در قسمت سازنده مقدار Interval را به یک عضو کلاس برای استفاده بعدی، انتساب بدین و FreeOnTerminate را برای سادگی کار True کنید.یک متد UpdateProgressBar برای پیشبرد ProgressBar1 و تعیین درصد پیشرفت باید داشته باشیم که بصورت Synchronize باید فراخوانی بشه؛ بطور خلاصه، این نوع فراخوانی باعث میشه که کامپوننت های روی فرم هنگام دستیابی همزمان Thread ها دچار مشکلات همزمانی نشه و مدیریت صحیح روشون اعمال بشه. البته راه های دیگه ای هم واسه این کار هست که فعلاً به اونها نمی پردازیم ...هر دو یونیت (فرم اصلی و Thread) باید همدیگه رو uses کنند، پس اینکار رو هم انجام بدین ...کد نهایی Thread بصورت زیر خواهد بود :unit Unit2;

interface

uses
  Math,
  Classes,
  SysUtils,
  ComCtrls;

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

implementation

uses Unit1;

{ TTestThread }

constructor TTestThread.Create(CreateSuspended: Boolean;
                               Interval: Integer);
begin
  inherited Create(CreateSuspended);
  FInterval := IfThen(Interval<=100, Interval, 1);
  FreeOnTerminate := True;
end;

procedure TTestThread.UpdateProgressBar;
begin
  Form1.ProgressBar1.Position :=
  Form1.ProgressBar1.Position + FInterval;
  Form1.Label1.Caption := IntToStr(StrToInt(Form1.Label1.Caption) + FInterval);
end;

destructor TTestThread.Destroy;
begin
  // Do Something destroy ...
  inherited;
end;

procedure TTestThread.Execute;
var
  idx: Integer;
begin
  for idx := 0 to (100 div FInterval) - 1 do begin
    Synchronize(UpdateProgressBar);
    Sleep(500);
  end;
  Terminate;
end;

end.

حالا برای رویداد Button1Click فقط کافیه یه نمونه (Instance) از TTestThread ایجاد کنید، و روند کار یه TThread رو ببینید، کد بعنوان مثال بصورت زیر خواهد بود :procedure TForm1.Button1Click(Sender: TObject);
begin
  TTestThread.Create(False, StrToIntDef(edtInterval.Text, 1));
end;


امیدوارم بتونیم این بحث رو با کمک دوستان ادامه بدیم ...

----------


## Hamid.Kad

> هر برنامه یک پروسه یا یک Thread داره پس برنامه هایی که عملیات سنگین دارند Thread برنامه نمیکشه و سیستم هنگ می کنه.پس میاند برا برنامه چنتا Thread یا نخ اضافه می کنند تا این بار اطلاعاتی که تک Thread می کشه رو تقسیم کنند تا برنامه هنگ نکنه.


دوست عزیز. اینجوری نیست. با اضافه کردن چند تا نخ (thread) قدرت برنامه شما اضافه نمیشه. حتی میشه گفت به دلیل سوئیچ کردن بین نخها ممکنه سرعت برنامه پایین تر هم بیاد(البته واضحه که در بعضی جاها تقریباً چاره ای جز استفاده از نخ نیست). بنظرم برای اینکه این مطلب رو متوجه بشید قسمت نخ های سیستم عامل رو بخونید. چون واقعاً ارزش داره که خوب متوجه بشید.اینکه دوستان زیاد توضیح نمیدن به این دلیله که یه کم سخته چند صفحه از مباحث اصلی سیستم عامل رو در چند خط بخواهیم توضیح بدیم.




> ولا دقیقا به چه درد می خوره. مثلا یه برنامه که با اجرای یه دستور هنگ میکنه Thread چجوری از هنگ سیستمو در میاره.


باز هم بنظرم بهتره به مباحث تئوریک سیستم عامل رجوع کنید. ولی برای اینکه سرنخی به شما بدم، دلیلش Thread Switching هست.

----------


## Saeed_m_Farid

یه نکته ای تو کد قبلی بود و گذاشته بودم واسه بعد بگم ولی الان که وقت هست، عرض میکنم :

فرض کنید کاربر دکمه رو زد و thread شما شروع بکار کرد، (عمداً دکمه غیرفعال نشده) حالا اگه دوباره دکمه Button1 فشار داده بشه چی میشه؟ 
اتفاقی که میافته اینه که قبل از اینکه thread قبلی از بین بره، thread جدیدی ایجاد میشه که دقیقاً به همون ProgressBar دسترسی پیدا میکنه، یعنی قبل از اینکه thread قبلی بعد اتمام حلقه Terminate بشه و خودبخود (به علت FreeOnTerminate := True) ازبین بره، این اتفاق میافته؛ و چون ما تابع دسترسی به اشیاء فرم رو Synchronize صدا کردیم، پس نتیجه این میشه که هر دو می تونن Position پروگرس ما رو جلو ببرن، و درصد از %100 بیشتر میشه! 

برای حل این مشکل چند تا کار میشه کرد :

*بدترین و آسان ترین* : یه flag (متغیر سراسری بولین) بذاریم تو یونیت فرم و هنگام شروع کار thread در تابع سازنده اون رو مقداردهی (True) کنیم و در پایان کار thread برش (False) گردونیم (مثلاً تو مخرب - Destroy)؛ در نتیجه می تونیم اگه اول thread دیدیم فلگ موردنظر مقداردهی شده thread رو Terminate می کنیم، یا اصلاً موقع کلیک Button1 نذاریم thread ایجاد بشه و پیغام خطا بدیم ...*روش پیغام* : این هم مثل روش قبلی ولی یکم بهتر، واسه thread مون یه متغیر سراسری (قبل) تعریف کرده و سعی می کنیم به فرم مون _یه جوری_ بفهمونیم که کار thread تموم شده، اگه کار تموم شده باشه thread رو از بین می بریم، بعدش اگه کاربر Button1 رو فشار داد اگه thread موجود بود که پیغام خطا میدیم بهش، در غیر اینصورت thread رو دوباره ایجاد می کنیم.*راه های دیگه* سخت تره، از اینها OK بگیریم بعد!
حالا _چطور_ بفهمونیم؟ این هم چندین روش داره که آسون ترینش رد و بدل کردن پیغام بین thread و فرم هست. این مورد هم قبلاً مکرراً تو سایت در موردش بحث شده، ولی واسه راهنمایی بیشتر بگم که از PostMessage از درون thread استفاده می کنیم، تو فرم مون هم یه ویندوز پروسیجر میذاریم که پیغام موردنظر رو گرفته و thread رو از بین ببره، البته باید توجه کنید که دیگه FreeOnTerminate رو نباید از درون thread مقداردهی کنید ...

برای راهنمایی و نکات کلیدی (از صفر تا مثلاً 13  :چشمک: ) تو سایت _Delphi About_ مثالهای متنوعی رو میتونید در این مورد ببینید، اگه اونها رو دیدید و باز هم مشکل داشتید، در خدمتیم ...

موفق باشید.

----------


## AbiriAmir

خب
حالا میخوام این تاپیک رو دوباره با سوالم زنده کنم

جناب Saeed_m_farid
شما از synchronize استفاده کردید و حداقل هممون با مشاهده تاپیک های دیگه ای که راجع به ترید هستن میفهمیم که synchronize در واقع کد رو تو ترید اصلی برنامه اجرا میکنه
پس به درد من و ایشون نمیخوره
راه حلمون چیه؟
یه سوالم از جناب delphi-7 دارم:
شما وژدانن ترید رو یاد گرفتید؟
الان با استفاده از ترید برنامتون هنگ نمیکنه؟

----------


## AbiriAmir

اصلا یه سوال دیگه
خود شما و بقیه ترید رو از کجا یاد گرفتید؟

----------


## FiACKER

> به نظرتون بهتر نیست به جای تحلیل سطح علمیه من کمک کنید و یه نمونه برنامه که یه thread کوچولو استفاده شده به عنوان مثال بزارید.


از اين بابت متاسفم. ببخشيد.




> وژدانن


شوخي : فك كنم درستش   وجداناً هست  :لبخند گشاده!: 




> الان با استفاده از ترید برنامتون هنگ نمیکنه؟


من نه صاحب نظرم نه متخصصم ولي فكر مي كنم :
تردينگ براي افزايش كارايي برنامه ها هست نه اينكه يه برنامه هنگ كنه يا نه.
چون به هر حال اگه يه كاره سنگين به ترد بديد شايد اونم هنگ كنه ولي حداقل تفاوتش اينه كه رويه كاركرده برنامه اصلي تاثيري نداره يا تاثيره كمي داره.




> خود شما و بقیه ترید رو از کجا یاد گرفتید؟


فكر نمي كنم بشه گفت من (شخص خودم...احمدم، احمد!)بلدم با ترد ها كار كنم.
ولي بهترين گزينه اينه كه بعد از تحقيق و ديدن سورس كد هايه مختلف بهتره در يه پروژه جدي از تردينگ استفاده كرد.


در هر حال معذرت مي خوام به خاطره بي ادبيم در پست هاي گذشته.

----------


## Saeed_m_Farid

> ...
> شما از synchronize استفاده کردید و حداقل هممون با مشاهده تاپیک های دیگه ای که راجع به ترید هستن میفهمیم که synchronize در واقع کد رو تو ترید اصلی برنامه اجرا میکنه
> پس به درد من و ایشون نمیخوره


من مشکل شما و ایشون رو متوجه نشدم تا بتونم جواب مرتبطی بدم که به دردتون بخوره، تا اونجایی که من فهمیدم آقا/خانم Delphi-7 میخواست یکمی بیشتر در مورد multi-threading بدونه و بقول خودشون "در لینکهایی که دوستان گزاشتند خیلی توجه کردم" ولی به نتیجه نرسیده بودن؛ پست های بنده در مورد کلیات برنامه های چند نخی و ساده ترین مثالی که به ذهنم رسید (و پیشبرد اون) بود؛ به هر صورت اگه قصدتون ادامه این تاپیک هست، با اجازه دوستان، یکمی ریزتر میشیم ...



> اصلا یه سوال دیگه
> خود شما و بقیه ترید رو از کجا یاد گرفتید؟


بنده بالشخصه، صادقانه بگم که شروع برنامه نویسی چندنخی برام با دلفی شروع نشد و بیشتر با سی++ و BCB6 درگیر بودم (یعنی "باید" داشت!)، و همونطوریکه جناب کشاورز گفتن من مجبور بودم با الگوریتمهای موازی کار کنم و انواع روشهای این کار رو بررسی کردم...
یعنی برنامه ام (حداقل) باید به 60 تا کانال همزمان قابلیت پاسخگویی میداشت، به نظر شما چه راهی میرسه؟ روی هر کانال عملیات مجزا و مستقل از هم انجام میشه و مجبوریم از طرف دیگه به Thread اصلی بگیم که هر کدوم از کانال هامون (Thread هامون) در چه وضعیتی بسر میبرن؟ چه اتفاقاتی (شامل چندین نوع عملیات مختلف) الان داره تو کانال موردنظر اتفاق میافته؟ هر جا لازمه واسه کانال و Thread موردنظر چیزی فرستاد و ...
از طرف دیگه بخاطر درگیری با سخت افزار مجبور بودیم سختی کار (بحث اش خیلی مفصله ...) با تردینگ سی رو به جون بخریم، بتدریج که تجربه مون بیشتر شد، وابستگی به سخت افزار منتفی شد و تونستیم بریم رو دلفی. اونوقته که شما قدر کلاس TThread رو می فهمید و سادگی و قابلیت اطمینان اش رو متوجه میشید ...
==================================================  ===================

روشهایی که برای Synchronization استفاده میشن برای اینه که در متدهایی که مطمئن نیستید Thread-Safe هستند یا نه، در استفاده از منابع مشابه conflict پیش نیاد، مثلاً تو مثال ما (پست های قبلی بنده در این تاپیک)، این منابع مشترک اشیاء موجود رو فرم اصلی (یا فرمهای دیگه) هست و روشی که برای اینکار تو اونجا استفاده شده بود پروسیجر Synchronize هست.

حالا اگه نیاز دارید که به اشیاء (یا نمونه های کلاس) خاصی، روی فرم دسترسی همزمان داشته باشید از این پروسیجر و سایر روش ها، کلاس ها یا متدهای مرتبط مثل CheckSynchronize، TCriticalSection، TMultiReadExclusiveWriteSynchronizer و ... استفاده می کنید، اگه کار دیگه ای میخواهید بکنید باید راه حل مرتبط با اون رو پیاده سازی کنید! من کی گفتم برای بالا رفتن سرعت (یا هر منظور دیگه ای که شما دارید و من نمیدونم چیه!) برنامه باید از Synchronize استفاده بکنه؟ هیچ ربطی نداره ...

شما دقیقاً باید بدونید که چی میخواهید، بعد برید سراغ Thread؛ برای برنامه نویسانی که دارن فقط رو رابط کاربری یا موارد مشابه کار میکنن، نیازی نیست برن دنبال Thread، برای اینکه بقول دوستمون خود Threadها هم نیاز به resource دارن و استفاده بیجا از اونها بیشتر سربار هست تا مفید فایده بودن؛ بنابراین استفاده از Threadها مثلاً برای بالا رفتن سرعت برنامه و بهینه شدن و ... کاملاً اشتباهه، چون در حقیقت هر Thread به همون اندازه Thread اصلی شما، منابع سیستم رو اشغال میکنه (هرچقدر هم که کم باشه)، اینطوری نیست که من حال میکنم تو اینکار از Thread استفاده کنم چون حالا دیگه بلدم از Thread استفاده کنم و ... بعبارت دیگه هر Thread به " time slice" مجزا تو CPU ایجاد میکنه، و مجبورش میکنه که task بیشتری رو پردازش کنه، پس تو امور معمولی Thread بیشتر باعث کاهش سرعت میشه تا افزایش سرعت!
مواردی که مثلاً استفاده از Thread می تونه مفید باشه :


پروژه شما طوری هست که مجبورید از الگوریتم های موازی استفاده کنید، مثلاً همون موردی که من چند سطر قبل عرض کردم، اکثر سیستم های مخابراتی اینطورین، یعنی شما راه فرار ندارین و البته که مدیریت Thread ها هم خیلی مهمه، چون هر لحظه (بصورت همزمان) تعداد زیادی از مشترکین دارن با سیستم شما کار میکنن و اگه قرار باشه از هر Thread یه آشغال رو سیستم بمونه یا منابعی آزاد نشه یه روز هم نمی کشه که کل Virtual Memory ویندوز پر میشه یا اصلاً برنامه تون منفجر میشه!


برنامه شما یه پردازش خیلی بزرگ رو مدیریت میکنه مثلاً کوئری های حجیم بانک اطلاعاتی یا محاسبات پیچیده زمان بر، که چندین دقیقه زمان می برن؛ تو اینحالت (تو برنامه هایWin-16  یا Win-32) رابط کاربری شما قفل میکنه یا بعبارت دیگه فریز میشه! ایجاد Thread های مجزا برای اینکار باعث میشه که پردازش موردنظر بره پشت صحنه و رابط کاربری شما آزاد بشه.


مطمئنید که برنامه شما از یه سیستم چند-پردازنده بهره میبره. برای مثال، Windows NT قابلیت کار با سیستم های SMP رو داره. با برنامه های Multi-Thread روی چنین سیستم هایی (هم سخت افزار و هم نرم افزار) شما مطمئن میشید که Thread های مجزا روی پردازنده های مجزا اجرا میشن و شما می تونید از تعادل و کارآیی بهینه روی پردازنده های سیستم بهره من بشید.


هیچ کدوم از شرایط بالا صادق نیست و شما از یک سیستم تک پردازنده و سیستم عامل معمولی استفاده می کنید ولی یه کار حجیم دارید تو برنامه تون انجام میدین که باید کاربر هم ببینه، مثلاً تو نمایش فرمتون هزار و صد تا کامپوننت و اسکین های خفن لود می کنید! بگذریم که کارتون ورسته یا نه، ولی شما تصمیمتو گرفتی و CPU بیچاره باید تمام این چیزهای "خوشگل" رو تو پردازش های در حد صفر و یک و الگوریتم های فوق پیچیده انجام بده، تجربه نشون داده که شکوندن الگوریتم سمت برنامه شما به راه حل های کوچک تر و انجام مستقل اونها، cycle های کمتری از CPU می گیره، حالا این وظیفه شماست و بقول آقای کشاورز، ازتون میخوان که : "راه حلی ارائه کنید که بشه اولا آن کار را به بخش های کوچکتری تقسیم کرد، و ثانیا آن بخش های کوچکتر را بطور مستقل از هم اجرا کرد." هروقت دقیقاً این مفهوم رو درک کردید و تونستید الگوریتم های Boxing رو تو بارگیری اجزاء فرم پیاده کنید با تقسیم قطعات کوچکتر برنامه بین Thread های مجزا کارآیی سیستم بطور قابل ملاحظه ای تغییر می کند (اگه تا اون موقع هنوز اصرار به این نوع برنامه نویسی داشته باشید!)

دارم میرم، امیدوارم بحث رو با هم ادامه بدیم ...!)

http://www.delphicorner.f9.co.uk/articles/op4.htm
http://www.delphicorner.f9.co.uk/articles/db1.htm

----------


## AbiriAmir

ببینید
من میخوام قفل Tiny رو توی یه ترید چک کنم
همین
تو ویندوز xp
راستی با postmessaage میشه پیغام ها رو به ترید مورد نظر فرستاد؟؟؟

----------


## Saeed_m_Farid

> ببینید
> من میخوام قفل Tiny رو توی یه ترید چک کنم
> همین
> تو ویندوز xp
> راستی با postmessaage میشه پیغام ها رو به ترید مورد نظر فرستاد؟؟؟


خدا رو شکر پروژه های ما طوری نیستند که به غیر از مشتریهای خاص به درد کس دیگه ای بخوره، بهمین علت زیاد در مورد قفلهای نرم افزاری/سخت افزاری تحقیق نکردم، ولی امیدوارم شما حداقل این تاپیک زیر رو مطالعه کرده باشی : *آیا قفل سخت افزاری TinyUSB شرکت منشور سیمین خوبه؟*
دوستان عزیز کراکر، آنتی پکر، پچر و ... حسابی دل و روده این قفل رو ریختن بیرون، مثل اینکه صحبت باج گیری و اینها هم بود !!!

=======================================

*در مورد ارسال پیام به Thread با PostMessage :*

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

در حالت کلی برای ارسال پیام به Thread از PostThreadMessage استفاده میشه، که در اینحالت هم باید ThreadID رو بدونید، یعنی یا یه جایی تمام ThreadID های Terminate نشده رو نگه دارید و یا از داخل Thread یه متد Public بنویسید که برای ارسال پیغام به Thread موردنظر اون متد (پروسیجر یا تابع) رو فراخوانی کنید ...

حالا اگه مرحله اول یعنی ارسال پیام به Thread رو انجام دادین، قسمت دوم یکمی سخت تره، یعنی باید تو Thread موردنظر به این پیغام رسیدگی بشه، و همونطورکه میدونید دیگه نمیتونیم Windows Procedure برای Thread بنویسیم (چون Thread پنجره نداره!)، پس کجا پیام رو هندل کنیم؟ نظر شما چیه؟  :متفکر: 

.
..
...

من (و دوستان) برای اینکار یه کلاس دیگه از TThread ارث میبرم که بالفرض اسمش رو میذاریم TMessageQueueThread؛ چون Thread ای هست که پیغامها رو در یه صف رسیدگی میکنه، این کلاس یه پروسیجر virtual داره (مثلاً ExecutionMessage) که وظیفه اش رسیدگی به Message هاست (مثل همون کاری که تو Windows Procedure تو فرمهای دلفی برای پردازش پیغامها می کنیم)، حالا تو تابع Execute هر موقعی که پیغام گرفتیم (با تابع GetMessage) این پروسیجر ExecutionMessage رو فراخوانی می کنیم ...

این کاری هست که باید انجام بشه، ولی این Thread منحصراً میشه یه Thread برای پردازش پیغامها و نمیشه مثلاً هم پیامها رو توش پردازش کرد و هم یه کار دیگه کرد! هر کاری داشتیم بهش میگیم که مثلاً با این پیام کار موردنظر ما رو (با یه Case تو پروسیجر ExecutionMessage برای Messageها) انجام بده، و اگه کار دیگه هم بود و کار قبلی تموم نشده باشه، میره تو صف Thread تا نوبتش برسه و انجام بشه.

تمام مراحل کار رو توضیح دادم ولی سورس رو نمیذارم تا ایده های شما رو هم بدونم و شاید تونستیم یه ایده بهتر واسه اینکار پیدا کنیم...

----------


## AbiriAmir

دا رو شکر پروژه های ما طوری نیستند که به غیر از مشتریهای خاص به درد کس دیگه ای بخوره، بهمین علت زیاد در مورد قفلهای نرم افزاری/سخت افزاری تحقیق نکردم، ولی امیدوارم شما حداقل این تاپیک زیر رو مطالعه کرده باشی : آیا قفل سخت افزاری TinyUSB شرکت منشور سیمین خوبه؟
دوستان عزیز کراکر، آنتی پکر، پچر و ... حسابی دل و روده این قفل رو ریختن بیرون، مثل اینکه صحبت باج گیری و اینها هم بود !!!
ممنون
این تاپیک رو خوندم ولی خداروشکر نرم افزار منم اختصاصیه و خیلی کسی نمیاد کرکش کنه
فقط قفل سخت افزاری گزاشتم که همینطوری کپی نشه
_{این قسمت به خاطر جلوگیری از به بیراهه کشیده شدن تاپیک حذف شد}_


-----------------------


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

----------


## Saeed_m_Farid

> ...
> ولی میخوام بدونم چجوری میشه از ترید استفاده کرد تا یه عملیاتی رو انجام بدیم بدون این که برنامه قفل بشه و فعلا کارم چک کردن قفله...


اول خواهش میکنم این "توضیحات قفلی" رو از پستت حدف کن که الان همه دوستان متخصص قفل و انجمن آچارسازان تشریف میارن اینجا و تاپیک بیراهه میره ...
فکر کنم در مورد "بدون این که برنامه قفل بشه"؛ هم اینجا کاملاً بحث شده و هم کلی پست و مقاله تو تالار در موردش هست، ولی بازم مشکلی بود بفرمایید ...

----------


## AbiriAmir

اگه مشکل نبود که...
خب مشکله
یعنی همش از synchronize استفاده شده که...
فایده ای نداره

----------


## Saeed_m_Farid

> یعنی همش از synchronize استفاده شده که...
> فایده ای نداره


چی فایده ای نداره؟ من متوجه منظور شما نمیشم.
چرا چسبیدین به synchronize؟ من یه مثال ساده زدم و در مورد به کامپوننت خاص قرار بود یه کاری بکنیم و تمام!
تا اونجایی که من فهمیدم : شما میخوای یه مقادیری بفرستی داخل Thread برای چک کردن قفل، بعد نتیجه رو بفرستی به Main که آیا برنامه، ادامه روند کار رو انجام بده یا نه؟ خوب این چه ربطی به synchronize داره؟ یا اینکه "کد رو تو ترید اصلی برنامه اجرا میکنه" یا نه؟  

راه حل نمونه: 

یه Thread می سازید، اگه مقادیری لازمه که هنگام اجرای Thread به اون بدید باید سازنده رو Override کنید، و مقادیر ورودی رو به Thread وارد کنید، مثلاً یه چیزی مثل قطعه کد زیر :
constructor TCheckLock.Create(bCreateSuspended: Boolean;
                              MyParam1,
                              MyParam2,
                              MyParam3 : String;
                              );
begin
  FreeOnTerminate := True;
  FFirstParam     := MyParam1; // یه متغیر خصوصی عضو کلاس Thread 
  FSecondParam    := MyParam2; 
  FThirdParam     := MyParam3; 
  // کارهایی که باید تو سازندا انجام بشه ...
  inherited Create(bCreateSuspended);
end;

سعی می کنید تو Thread، تو یه حالتی که فقط بررسی شرط نباشه (جهت اطمینان)، مقایسه ها رو بصورت یه فلگ Hash شده به Main برگردونید و در یه Case خاص کلیدهای Hash شده بررسی شوند ...

در پایان کارِتون برای بررسی قفل، یه پیغام توسط به Main میفرستید که کارتون با قفل تموم شده و یا مشکل چی بوده؛ در نهایت هم یه ویندوز پروسیجر (_تو این پست_ توضیحاتی در این مورد عرض کردم) برای پردازش پیامهای رسیده از Threadمیذارید که پیغام فرستاده شده توسط PostMessage رو رسیدگی کنه ...

----------


## AbiriAmir

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

----------


## AbiriAmir

یه جورایی متوجه نمیشم :گریه:  :گریه:  :گیج:  :گیج: 
اگه یه سورس کوچیک بدین منون میشم :خجالت: 
یعنی منظورم اینه که همین کدهایی که اینجا نوشتین رو به صورت سورس آپلود کنین
به حر هال ممنون

----------


## Saeed_m_Farid

> نمیشه به جای این که به فرم چیزی ارسال کنیم مستقیما توی ترید بنویسیم که برنامه بسته بشه و یا هر کار دیگه؟؟؟


چرا نمیشه! یه خط کد زیر هست ولی من اونهمه مطلب عرض کردم تا کاری کنید که نشه به همین راحتی اون قسمت از کد رو عوض کرد.
والا تو Thread بنویسید "اونی که من میخوام" <> if Tiny.key بعد کد پایین! فردا هم هرکی خواست بره یه Memory Dump از اون تکه کدتون ورداره و قسمت مقایسه رو کامنت کنه و یا بجاش یه ShowMessage کنه که "به به! چه حالی می کنیم ما ..."

PostMessage(Application.Handle, WM_CLOSE, 0, 0);




> یه جورایی متوجه نمیشم
> اگه یه سورس کوچیک بدین منون میشم
> یعنی منظورم اینه که همین کدهایی که اینجا نوشتین رو به صورت سورس آپلود کنین
> به حر هال ممنون


یه سورس کوچیک از چی بدم؟ شما کدتون رو بذارید تا ببینیم کجاش (در مورد Multi-Threading) مورد دارید؟ چون این تاپیک قرار بوده در مورد "*آموزش قدم به قدم thread*" باشه، و در حقیقت ما یه سولوشن در مورد یه مبحث خاص رو جلو نمی بریم؛ پس لطف کنید سوالتون رو (موردی) در خصوص Threading مطرح کنید(یعنی یه قسمتی رو بنویسید و جاییش که مشکل دارید رو مطرح کنید) ...

موفق باشید.

----------


## zidane

اين همه درد سر نداره!
به راحتي از کامپوننت Background Worker استفاده کنيد

----------


## Saeed_m_Farid

> اين همه درد سر نداره!
> به راحتي از کامپوننت Background Worker استفاده کنيد


اصلاً چرا برنامه نویسی می کنیم و اینهمه دردسر می کشیم؟ بریم سر خیابون لَبو بفروشیم، زمستونم که داره میاد!
آخه دوست عزیز، عنوان این تاپیک رو دقیق نگاه کنید نوشته شده :   آموزش قدم به قدم thread
نه حل مسائل، اونهم از روش *"راه در رو"* : همه چی رو نمیشه با اینجور کامپوننت ها حل کرد، من خدمت دوستان تو *این پست* سناریوهایی عرض کردم که multi-threading براشون کاربرد داره و این موضوع ادامه بحث ادامه داری بود که در پیرو صحبت ها اومد ...

----------


## babakmomeni

> اصلاً چرا برنامه نویسی می کنیم و اینهمه دردسر می کشیم؟ بریم سر خیابون لَبو بفروشیم، زمستونم که داره میاد!
> آخه دوست عزیز، عنوان این تاپیک رو دقیق نگاه کنید نوشته شده :   آموزش قدم به قدم thread
> نه حل مسائل، اونهم از روش *"راه در رو"* : همه چی رو نمیشه با اینجور کامپوننت ها حل کرد، من خدمت دوستان تو *این پست* سناریوهایی عرض کردم که multi-threading براشون کاربرد داره و این موضوع ادامه بحث ادامه داری بود که در پیرو صحبت ها اومد ...


سلام. اول از همه، سپاس بابت پیگیری این تاپیک. من از thread ها استفاده کرده و می کنم ولی این تاپیک مفید رو هم قدم به قدم دنبال کردم و محظوظ و مستفید هم شدم. در پاسخ به دوست گرامی zidane، در تکمیل فرمایشات شما، باید عرض کنم که مبحث multi-threading نه تنها در دلفی بلکه در هر زبان برنامه نویسی اونقدر مهمه که به نظر حقیر در صورت متوجه نشدن اون، استفاده از این *راه در رو* ها علاوه بر اینکه مشکل برنامه نویس رو کمتر نمی کنن، بلکه بیشتر مسئله ساز خواهند شد. مسلما این دست کامپوننت ها هم از threading استفاده می کنن و فقط برنامه نویس رو از شر تعاریف یک ترید در برنامه نجات می دن. حالا تصور کنین بنده ای که مفهوم multi-threading رو کامل متوجه نشدم از این *در رو* استفاده کنم و بخوام برنامه رو دیباگ کنم، وامصیبتا!! بیا و درستش کن. به هر رو، خواهش دارم با ادامه این مبحث مفید، بقیه عزیزان و در وهله اول بنده رو در تجربیاتتون سهیم بفرمایین.

----------

