PDA

View Full Version : استفاده از thread در یک قطعه برنامه و جوابهای متفاوت با F5 و F11..



Fariba_NJ
چهارشنبه 12 تیر 1387, 12:09 عصر
سلام، در کد زیر چرا وقتی برنامه با F5 اجرا میشه جواب درسته اما وقتی می خوام از F11 استفاده کنم برنامه بدون در نظر گرفتن Thread ها اجرا میشه؟


using System;
using System.Threading;

// Simple threading scenario: Start a static method running
// on a second thread.
public class ThreadExample
{
// The ThreadProc method is called when the thread starts.
// It loops ten times, writing to the console and yielding
// the rest of its time slice each time, and then ends.
public static void ThreadProc()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("ThreadProc: {0}", i);
// Yield the rest of the time slice.
Thread.Sleep(0);
}
}

public static void Main()
{
Console.WriteLine("Main thread: Start a second thread.");
// The constructor for the Thread class requires a ThreadStart
// delegate that represents the method to be executed on the
// thread. C# simplifies the creation of this delegate.
Thread t = new Thread(new ThreadStart(ThreadProc));
// Start ThreadProc. On a uniprocessor, the thread does not get
// any processor time until the main thread yields. Uncomment
// the Thread.Sleep that follows t.Start() to see the difference.
t.Start();
//Thread.Sleep(0);

for (int i = 0; i < 4; i++)
{
Console.WriteLine("Main thread: Do some work.");
Thread.Sleep(0);
}

Console.WriteLine("Main thread: Call Join(), to wait until ThreadProc ends.");
t.Join();
Console.WriteLine("Main thread: ThreadProc.Join has returned. Press Enter to end program.");
Console.ReadLine();
}
}


عکسهای نتایج اجرا را هم ضمیمه کردم. یکی با F5 ودیگری با F11.
با تشکر.

رضا عربلو
چهارشنبه 12 تیر 1387, 16:16 عصر
نتیجه این تفاوت به خاطر ماهیت اصلی thread ها است.thread ها در هنگام اجرا مقید به یک AppDomain نمی باشند و می توانند بین Appdomain ها حرکت کنند. در واقع هنگامی که شما یک Thread را استارت می کنید هیچ تضمینی وجود ندارد که بلافاصله اجرا شود و یا در هنگام اجرا تا پایان thread برنامه اصلی شما (Primary Thread ) بصورت Freezed بماند. بلکه CLR تنها تضمین می کند در اولین فرصت ممکن که مناسب دانست Thread های شما را بر اساس Priority آنها اجرا کند و هر موقع که لازم دانست کنترل به به یک Thread دیگر بدهد.
برای رفع این مشکل می توانید از Delegate ها استفاده کنید و یا آن قسمتی ار کدتان را که می خواهید بصورت یکجا اجرا شوند درون دستور lock بگذارید.به اینصورت:


public static void ThreadProc()
{
static object x = new object();
lock(x) {

for (int i = 0; i < 10; i++)
{
Console.WriteLine("ThreadProc: {0}", i);
// Yield the rest of the time slice.
Thread.Sleep(0);
}
}
}

Fariba_NJ
چهارشنبه 12 تیر 1387, 16:33 عصر
_پس در این صورت اگه بخوام برنامه ای که از نخ ها استفاده می کنه را بصورت خط به خط اجرا کنم راهی وجود نداره؟ چطور trace ش کنم؟
_ و در ضمن من نمی خوام اینجا قسمتی از برنامه ام یکجا اجرا بشه (گرچه می دونم threadها روشی برای پیاده سازی این مورد هستند) اینجا می خوام مرتباً بین 2 تا thread حرکت کنم. یکی thread اصلی بدنه برنامه و دیگری thread ی که خودم ایجاد کردم.
_و اگر براتون امکان داره طریقه ی استفاده از delegate ها را تو همین مثال خودم کمی برام توضیح بدید. دقیقا چه دستوری؟
تشکر.

mehdi.mousavi
چهارشنبه 12 تیر 1387, 16:41 عصر
_پس در این صورت اگه بخوام برنامه ای که از نخ ها استفاده می کنه را بصورت خط به خط اجرا کنم راهی وجود نداره؟ چطور trace ش کنم؟
_ و در ضمن من نمی خوام اینجا قسمتی از برنامه ام یکجا اجرا بشه (گرچه می دونم threadها روشی برای پیاده سازی این مورد هستند) اینجا می خوام مرتباً بین 2 تا thread حرکت کنم. یکی thread اصلی بدنه برنامه و دیگری thread ی که خودم ایجاد کردم.
_و اگر براتون امکان داره طریقه ی استفاده از delegate ها را تو همین مثال خودم کمی برام توضیح بدید. دقیقا چه دستوری؟
تشکر.

سلام.
نمیدونم اطلاع دارید Sleep(0) چیکار میکنه یا تصادفا این پارامتر رو صفر رد کردین. وقتی عدد صفر رو بعنوان پارامتر به تابع Sleep میدین، در واقع دارید به سیستم میگید که "thread فعلی رو suspend کن تا بقیه thread هایی که منتظر اجرا شدن هستن، اجرا بشن." از این مساله در واقعیت فقط و فقط در شرایط خیلی خیلی نادر استفاده میشه و شما نباید اونو به این سادگی در کدتون بکار ببرین.

اما از این مساله که بگذریم، شما با استفاده از Synchronization Object ها میتونید روند همزمانی دو یا چند Thread رو کنترل کنید تا مشکلی که آقای عربلو به اون اشاره کردن، مرتفع بشه. برای مثال در این زمینه میتونید به MSDN مراجعه کنید.

رضا عربلو
چهارشنبه 12 تیر 1387, 16:42 عصر
اگر ممکن است مرتباً بین دو Thread حرکت کنید نباید انتظار داشته باشید که همواره نتیجه یکسان باشند.

طریغه استفاده از delegate به این صورت است.


delegate void MyDlegateType();

Main()
{
...
MyDelegateType MyDelegate = new MyDelegateType(ThreadProc);
MyDelegate.Invoke();
}

Fariba_NJ
چهارشنبه 12 تیر 1387, 16:57 عصر
سلام.
نمیدونم اطلاع دارید Sleep(0) چیکار میکنه یا تصادفا این پارامتر رو صفر رد کردین. وقتی عدد صفر رو بعنوان پارامتر به تابع Sleep میدین، در واقع دارید به سیستم میگید که "thread فعلی رو suspend کن تا بقیه thread هایی که منتظر اجرا شدن هستن، اجرا بشن." از این مساله در واقعیت فقط و فقط در شرایط خیلی خیلی نادر استفاده میشه و شما نباید اونو به این سادگی در کدتون بکار ببرین.

اما از این مساله که بگذریم، شما با استفاده از Synchronization Object ها میتونید روند همزمانی دو یا چند Thread رو کنترل کنید تا مشکلی که آقای عربلو به اون اشاره کردن، مرتفع بشه. برای مثال در این زمینه میتونید به MSDN مراجعه کنید.


_خب من دقیقاً می خوام همین کار را کنم یعنی thread ی را از اجرا خارج کنم تا thread بعدی اجرا بشه. در واقع می خوام خودم thread ها را مدیریت کنم! میشه؟
راه دیگه ای هم برای این منظور غیر از متد sleep وجود داره؟


_و سوالی که الآن به ذهنم رسید اینکه می تونم برای thread ها زمان تعیین کنم؟ یعنی thread شماره 1 فرضاً 500 میلی ثانیه اجرا بشه و بعد از اون کنترل برنامه به thread های دیگه واگذار بشه؟ (این کارها با روش های مرسوم استفاده از thread ها خیلی فاصله داره و پرته؟ یا میشه این جوری هم کار کرد؟)


ممنون از وقتی که می گذارید و جواب میدید.

mehdi.mousavi
چهارشنبه 12 تیر 1387, 17:42 عصر
_خب من دقیقاً می خوام همین کار را کنم یعنی thread ی را از اجرا خارج کنم تا thread بعدی اجرا بشه. در واقع می خوام خودم thread ها را مدیریت کنم! میشه؟
راه دیگه ای هم برای این منظور غیر از متد sleep وجود داره؟


_و سوالی که الآن به ذهنم رسید اینکه می تونم برای thread ها زمان تعیین کنم؟ یعنی thread شماره 1 فرضاً 500 میلی ثانیه اجرا بشه و بعد از اون کنترل برنامه به thread های دیگه واگذار بشه؟ (این کارها با روش های مرسوم استفاده از thread ها خیلی فاصله داره و پرته؟ یا میشه این جوری هم کار کرد؟)

ممنون از وقتی که می گذارید و جواب میدید.

سلام.
مدیریت اصلی Thread در واقع بعهده سیستم عامل هستش. سیستم عامل هستش که تصمیم میگیره (بر اساس مشخصه های CPU و ...) که چه هنگام execution cycle رو به کدوم Thread بسپره. یه CPU تک هسته ای رو در نظر بگیرید. در چنین CPU هایی، سیستم عامل در Time-Slice های مورد نظر خودش، زمانی رو برای اجرای یه Threadدر نظر میگیره و اونو Resume میکنه. حالا چهار CPU تک هسته ای روی یه سیستم رو در نظر بگیرید. در چنین سیستمهایی به شرط اینکه سیستم عامل RTOS یا Real-Time OS باشه، 4 execution path بطور موازی وجود خواهد داشت.

شما میتونید از سیستم عامل بخواهید که Thread 3 رو در وضعیت Suspend قرار بده، تا Thread های 1، 2 و چهار در حالت Running بمونن. اما وقتی در Thread 3 از Sleep(0) استفاده میکنید، سیستم عامل خودش تشخیص میده که اجرا رو به کدومیک از Thread های 1، 2 یا چهار بسپره. اینجا شما هیچ کنترلی روی ترتیب اجرای thread ها ندارید.

Synchronization Object ها، همونطور که در پست قبلی هم اشاره کردم، به این منظور استفاده میشن. در واقع اینها Object هایی هستن که Handle اونها در Kernel مدیریت میشه و میشه اونها رو بدون ترس از چند Thread مورد دسترس قرار داد.

Mutex، Semaphore، Waitable Timer و Event ها میگن Synchronization Object. هر کدوم کاربرد خاص خودشون رو دارن و برای تطبیق همزمانی چند Thread مورد استفاده قرار میگیرن.

اگر به این لینک مراجعه کنید (http://msdn.microsoft.com/en-us/library/ms686364%28VS.85%29.aspx)، توضیحاتی در مورد هر کدوم میتونید بخونید. در هر حال، باید بگم که Debug کردن نرم افزارهای Multithreaded، با ابزارهای امروزی تقریبا ناممکن یا بسیار بسیار دشوار هستش.

vcldeveloper
چهارشنبه 12 تیر 1387, 17:54 عصر
Thread ها راهی برای اجرای دو یا چند پردازش بصورت موازی ارائه میدن. در واقع وقتی که یک Process شروع میشه، یک Thread به اون اختصاص پیدا میکنه که اون Thread به عنوان Thread اصلی برنامه شناخته میشه. یکی از وظایف این Thread بروز کردن رابط گرافیکی کاربر هست. اگر برنامه نویس نیاز به Thread های دیگه ایی در کنار این Thread داشته باشه، میتونه آنها را بوجود بیاره. در صورت خارج شدن Thread اصلی برنامه از حافظه، Thread های وابسته به آن هم که توسط برنامه نویس ایجاد شده بودند، هم از حافظه خارج میشند.
علت استفاده از Thread در برنامه ها اینه که ویندوز زمان CPU را بین Thread های در حال اجرا تقسیم میکنه، نه بین Process های در حال اجرا. ویندوز تمام Thread های در حال اجرا (از هر Processایی) را بر اساس اولویت آنها در یک صف قرار میده؛ یعنی هر چه اولویت یک Thread بالاتر باشه، در صف جلوتر قرار میگیره. به این ترتیب نوبت هر Thread که رسید، CPU در اختیار آن Thread قرار میگیره تا درخواست های آن Thread را پردازش کنه. وقتی زمان اختصاص داده شده به یک Thread تمام میشه، ویندوز اطلاعات مربوط به آن را ذخیره کرده و کنترل CPU را از آن Thread می گیرد و به Thread بعدی میده.
وقتی به Threadایی میگید که Sleep بشه، اولویت اون Thread تا پایین ترین حد کاهش پیدا میکنه. به این ترتیب سایر Threadها - که اولویت بالاتری از آن Thread دارند - در صف بالاتر از آن Thread قرار می گیرند.

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


خب من دقیقاً می خوام همین کار را کنم یعنی thread ی را از اجرا خارج کنم تا thread بعدی اجرا بشه. در برنامه های Multi-threaded گاهی لازم هست که Thread ها با هم همزمان شوند، یعنی یک یا چند Thread در زمان هایی منتظر یک یا چند Thread دیگر بمانند. در این شرایط باید مکانیزمی وجود داشته باشه که بتوان به Thread ها فهماند تا زمان خاصی یا تا زمان وقوع یک رویداد خاص یا یک شرط خاص، منتظر یک یا چند Thread دیگر بمانند، یا چند Thread نیاز دارند که به یک داده اشتراکی دسترسی داشته باشند، به تکنیک های مربوط به این کار Thread Syhcnronization گفته میشه. در ویندوز از انواع اشیاء (Synchronization Objects) برای همزمان سازی استفاده میشه، مثل CriticalSection, Mutex, Semaphor, Event و... هر یک از این روش ها مزایا و معایبی دارند و در جای خود استفاده می شوند. در CriticalSection که ساده ترین آنها هست، هر Thread ایی که در حال اجرا هست، برای اجرای بخشی از کد خود یک شی که بین همه Thread ها مشترک است را در اختیار می گیرد، اگر سایر Thread ها قصد اجرای آن بخش از ک را داشته باشند، باید منتظر Thread در حال اجرا بمانند تا شی مربوطه را آزاد کند؛ مثلا اگر 3 Thread به متغیر A دسترسی دارند، هر زمان که یک Thread در حال نوشتن در A هست، سایر Thread - در صورت استفاده از همزمان سازی - برای خواندن یا نوشتن مقدار در A باید صبر کنند تا نوشتن Thread اول تمام شود.
همزمان سازی باید با دقت صورت گیرند، وگرنه ممکن است منجر به مشکلاتی مثل Race Condition یا Deadlock شود.

فکر کنم این توضیحات مختصر و Keyword هایی که مطرح شد، بتواند به شما کمک کند که تحقیقی در این زمینه انجام بدید.

دقت کنید که فعلا کدهای آزمایشی مربوط به Multi-threading خود را بصورت برنامه های Console بنویسید و از برنامه های با رابط گرافیکی فعلا استفاده نکنید، چون بعدا متوجه میشید که رابط کاربر توسط Thread اصلی بروز میشه و سایر Thread ها هم اگر بخوان تغییری در رابط کاربر بدند، باید از طریق Thread اصلی این کار را انجام بدند. در دات نت بطور کلی اگر بخواهید در یک Thread به هر یک از اجزاء رابط کاربر که توسط Thread دیگه ایی ساخته شده، دسترسی داشته باشید، یک Exception دریافت می کنید.

در هنگام نوشتن پست، پست mehdi6755 (http://barnamenevis.org/forum/member.php?u=41233) هنوز ارسال نشده بود. در هر حال، با توجه به اون پست، اکثر مطالب این پست تکراری هستند.