PDA

View Full Version : Threads, Events & Mutexes در سی شارپ ، قسمت سوم



Vahid_Nasiri
جمعه 21 آذر 1382, 12:57 عصر
مثال یازدهم :


using System.Threading;

public class yyy
{
public void abc()
{
for ( ; ; ) ;
}
}

public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Start();
bool b = t.Join(10000);
System.Console.WriteLine("Over " + b);
}
}

Output
Over False


تابع Join یک عدد را بعنوان پارامتر که بیانگر حداکثر طول مدت به میلی ثانیه است می پذیرد و آن زمانی است که برای تکمیل یک ترد صبر خواهد شد. در مثال فوق حلقه ی for تعریف شده هیچگاه خاتمه نمی یابد. بنابراین ترد تا ابد اجرا خواهد شد. اما در اینجا تابع join به مدت 10 ثانیه صبر می کند تا ترد خاتمه یابد و سپس مقدار false را بر می گرداند.
می توان نتیجه گرفت که ما برای تصمیم گیری در مورد طول مدت زمانی که صبر خواهیم کرد تا یک ترد اجرایش تکمیل شود مختار هستیم. نباید فراموش کرد که برنامه ی ما هنوز خاتمه نیافته است و در حالت هنگ بسر می برد و صرفا با استفاده از task manager و end task کردن آن می توان سبب خاتمه ی برنامه شد. راه دیگر برای خاتمه ی این وضعیت استفاده از تابع Abort پس از تابع WriteLine می باشد.



مثال دوازدهم :


using System.Threading;

public class yyy
{
public void abc()
{
for ( ; ; ) ;
}
}

public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Join();
}
}


Output
Unhandled Exception: System.Threading.ThreadStateException: Thread has not been started.
at System.Threading.Thread.Join()
at zzz.Main()

اگر تردی در حال اجرا نباشد تابع Join سبب ایجاد یک ThreadStateException خواهد شد.



مثال سیزدهم :


using System.Threading;

public class yyy
{
public void abc()
{
System.Console.WriteLine("abc");
}
}

public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Start();
Thread.Sleep(3);
t.Abort();
System.Console.WriteLine("Over");
Thread.Sleep(100);
t.Start();
}
}

Output
abc
Over
Unhandled Exception: System.Threading.ThreadStateException: Thread is running or terminated. Cannot restart.
at System.Threading.Thread.StartInternal(IPrincipal principal, StackCrawlMark & stackMark)
at System.Threading.Thread.Start()
at zzz.Main()


در ابتدا بوسیله ی فراخوانی تابع Start سبب اجرای ترد t می شویم. سپس یک Sleep کوتاه در این ترد پدید می آوریم. در ادامه سبب Abort شدن آن گشته و Sleep می نماییم برای مدتی کوتاه (!) و سپس خاتمه . پس از مرگ یک ترد سعی شده است که تابع Start دوباره فراخوانی شود ، بنابراین سبب ایجاد یک خطا خواهد گردید.



مثال چهاردهم :


using System.Threading;

public class yyy
{
public void abc()
{
System.Console.WriteLine("abc");
}
}

public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Start();
Thread.Sleep(3);
t.Abort();
System.Console.WriteLine("Over");
Thread.Sleep(100);
try
{
t.Start();
}
catch (ThreadStateException e)
{
System.Console.WriteLine("In Exception "+e.ToString() );
}
}
}


Output
abc
Over
In Exception

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

• ArgumentNullException : هنگامی فراخوانی می شود که سازنده delegate نداشته باشد.
• SecurityException : هنگامیکه یک برنامه مجوز کافی برای ایجاد ترد نداشته باشد.



مثال پانزدهم :


using System.Threading;

public class yyy
{
public void abc()
{
System.Console.WriteLine("abc");
}
}

public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
System.Console.WriteLine(t.ApartmentState);
t.ApartmentState = ApartmentState.STA;
t.Start();
System.Console.WriteLine(t.ApartmentState);
}
}


Output
Unknown
STA
abc

همانند انسانها ، تردها نیز دارای آپارتمان هستند! هر تردی می تواند در خواست نماید که در یک single-threaded apartment و یا multi-threaded apartment اجرا گردد. این مورد با استفاده از خاصیت ApartmentState در هنگام اجرای برنامه و یا در آغاز کار آن قابل تنظیم است. مقادیری که یک ApartmentState می تواند داشته باشد به شرح زیر هستند :

• STA : Single Threaded Apartment
• MTA : Multi Threaded Apartment
• Unknown : مقدار پیش فرض است هنگامیکه هیچ مقداری تنظیم نشده باشد.



مثال شانزدهم :


using System.Threading;

public class yyy
{
public void abc()
{
System.Console.WriteLine("abc " + Thread.CurrentThread.IsBackground);
}
}

public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
System.Console.WriteLine("Main " + Thread.CurrentThread.IsBackground);
t.Start();
System.Console.ReadLine();//show results!
}
}

Output
Main False
abc False

یک ترد یا در background اجرا می شود و یا در foreground . خاصیت IsBackground ، مشخص کننده ی این حالت است. باید خاطر نشان کرد ، تردی که در background اجرا می شود با بسته شدن برنامه به صورت خودکار خاتمه خواهد یافت.



مثال هفدهم :


using System.Threading;

public class yyy
{
public void abc()
{
for ( int i = 0 ; i<=100; i++)
{
System.Console.WriteLine("abc " + i);
Thread.Sleep(1);
}
}
}

public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
System.Console.WriteLine("Main " + Thread.CurrentThread.IsBackground);
t.IsBackground = true;
t.Start();
Thread.Sleep(10);
}
}


Output (t.IsBackground = true)
Main False
abc 0

Output (t.IsBackground = false)
Main False
abc 0
abc 1
abc 2
..
..
abc 100

هنگامیکه t.IsBackground از true به false تنظیم می شود ، خروجی برنامه ، اجرای تابع abc را نمایش خواهد داد. با تغییر خاصیت IsBackground به true ، هنگامیکه برنامه اصلی خاتمه یابد ، ترد نیز پایان می پذیرد. بنابراین حلقه ی فوق زمانی را برای نمایش اعداد از صفر تا صد نخواهد داشت. در این حالت برنامه یک abc را با مقدار صفر نمایش می دهد.

از Sleep ها به این جهت استفاده شد تا خاتمه یافتن ترد اول و آغاز دومین ترد به شکل ملموس تری انجام شود. با تغییر خاصیت IsBackground به false ، ترد زمان لازم را برای اجرای کدش بدون هیچگونه توجهی به اولین ترد که آیا کارش را تکمیل کرده است یا خیر ، خواهد یافت . بنابراین foreground threads به روشی دقیقا مشابه با background threads ، هنگامیکه خاصیت فوق به true تنظیم شده است ، عمل می نمایند.

kablayi
جمعه 23 بهمن 1383, 06:32 صبح
:موفق:

bahman.net
جمعه 08 اردیبهشت 1385, 02:06 صبح
ممنون جالبه