آموزشگاه برنامه نویسی تحلیل داده
آموزشگاه برنامه نویسی تحلیل داده

Multi Treading در C#

دوره های مرتبط با این مقاله

Multi Treading

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


چرخه‌ی عمر Thread

چرخه‌ی عمر یک Thread زمانی آغاز می‌شود که شیئی از کلاس System.Threading.Thread ایجاد شود و با تمام شدن اجرا نیز به پایان می‌رسد.
در زیر می‌توانید حالت‌های مختلف چرخه‌ی عمر یک Thread را مشاهده کنید:

  • حالت آغاز نشده: این حالت مربوط به موقعیتی است که نمونه‌ی Thread ایجاد شده است اما متد Start فراخوانی نشده است.
  • حالت آماده‌باش: این حالت مربوط به زمانی است که Thread آماده به اجرا است و در حال انتظار برای چرخه‌ی CPU می‌باشد.
  • حالت غیر قابل اجرا: Thread‌ها زمانی قابل اجرا نیستند که:
    • متد Sleep فراخوانی شده باشد.
    • متد Wait فراخوانی شده باشد.
    • این Thread توسط عملیات ورودی/خروجی مسدود شده باشد.
  • حالت مرگ: این حالت مربوط به زمانی است که اجرای Thread با موفقیت و یا به صورت ناموفق تمام شده باشد.

Thread‌ اصلی (Main Thread)

در C# کلاس System.Threading.Thread در مواقعی کاربرد دارد که بخواهیم با چندین Thread کار کنیم. با استفاده از این کلاس می‌توان تک تک Thread‌ها را در یک برنامه‌ی چند Thread‌ای ایجاد کرد و به آن‌ها دسترسی پیدا کرد. به اولین Thread‌ای که قرار است در یک فرآیند اجرا شود Thread‌ی اصلی گفته می‌شود.
زمانی که یک برنامه‌ی C# شروع به اجرا شدن می‌کند، Thread‌ی اصلی به صورت خودکار ایجاد می‌شود. Thread ‌هایی که با استفاده از کلاس Thread ایجاد می‌شوند، Thread‌های فرزند Thread‌ی اصلی نامیده می‌شوند. می‌توانید با استفاده از ویژگی CurrentThread کلاس Thread دسترسی پیدا کنید.
در برنامه‌ی زیر اجرای Thread‌ی اصلی نشان داده شده است:

using System;
using System.Threading;
namespace MultithreadingApplication {
 class MainThreadProgram {
 static void Main(string[] args) {
 Thread th = Thread.CurrentThread;
 th.Name = "MainThread";
         
 Console.WriteLine("This is {0}", th.Name);
 Console.ReadKey();
 }
 }
}

زمانی که کد بالا کامپایل و اجرا شود، نتیجه به صورت زیر نمایش داده می‌شود:

This is MainThread

ویژگی‌ها و متدهای کلاس Thread

در جدول زیر برخی از پرکاربردترین ویژگی‌های کلاس Thread نشان داده شده است:

ردیف
ویژگی‌ها
توضیحات
1
CurrentContext
زمینه‌ی فعلی که Thread در حال اجرا شدن در آن است را دریافت می‌کند.
2
CurrentCulture
فرهنگ Thread‌ی فعلی را دریافت یا ارسال می‌کند.
3
CurrentPrinciple
اصول فعلی Thread را (برای امنیت مبتنی بر نقش) دریافت یا ارسال می‌کند.
4
CurrentThread
Thread‌ای که در حال اجرا است را دریافت می‌کند.
5
CurrentUICulture
فرهنگ فعلی مورد استفاده‌ی Resource Manager را جهت جستجوی منابع مختص به فرهنگ در زمان اجرا را دریافت یا ارسال می‌کند.
6
ExecutionContext
یک شیء ExecutionContext را دریافت می‌کند، به گونه‌ای که این شیء شامل اطلاعاتی درباره‌ی زمینه‌های متعدد Thread‌ی فعلی است.
7
IsAlive
مقداری را دریافت می‌کند که وضعیت اجرای Thread‌ی فعلی را نشان می‌دهد.
8
IsBackground
مقداری را دریافت یا ارسال می‌کند که پس‌زمینه بودن یا نبودن یک Thread را نشان می‌دهد.
9
IsThreadPoolThread
مقداری را دریافت می‌کند که متعلق بودن یا نبودن یک Thread به گروه مدیریت‌ شده‌ی Thread‌ها را نشان می‌دهد.
10
ManagedThreadId
شناسه‌ی منحصر به فردی را برای Thread‌ی مدیریت‌شده‌ی فعلی دریافت می‌کند.
11
Name
اسم Thread را دریافت یا ارسال می‌کند.
12
Priority
مقداری را دریافت یا ارسال می‌کند که اولویت زمان‌بندی یک Thread را نشان می‌دهد.
13
ThreadState
مقداری را دریافت می‌کند که شامل وضعیت Thread‌ی فعلی است.

در جدول زیر برخی از متدهای پرکاربرد کلاس Thread نشان داده شده است:

ردیف
متد
توضیحات
1
public void Abort()
یک ThreadAbortException را در Thread‌ای که ThreadAbortException احضار شده است، پیش می‌آورد تا فرآیند اتمام Thread آغاز شود. فراخوانی این متد معمولاً باعث تمام شدن Thread می‌شود.
2
public static LocalDataStoreSlot AllocateDataSlot()
شیار داده‌ای بی‌نامی را به تمامی Thread‌ها تخصیص می‌دهد. برای رسیدن به عملکرد بهتر از فیلدهایی استفاده کنید که با استفاده از صفت ThreadStaticAttribute نشان شده‌اند.
3
public static LocalDataStoreSlot AllocateNamedDataSlot(string name)
شیار داده‌ای نام داری را به تمامی Thread‌ها تخصیص می‌دهد. برای رسیدن به عملکرد بهتر از فیلدهایی استفاده کنید که با استفاده از صفت ThreadStaticAttribute نشان شده‌اند.
4
public static void BeginCriticalRegion()
یک میزبان را قبل از ورود فرآیند اجرا به منطقه‌ی کدها مطلع می‌کند. به گونه‌ای که در این کد اثرات لغو شدن یک Thread و یا یک استثنای کنترل نشده ممکن است باعث به خطر انداختن کارهای دیگر موجود در دامنه‌ی برنامه شود.
5
public static void BeginThreadAffinity()
یک میزبان را پیش از اجرای دستورالعمل توسط کد مدیریت‌شده مطلع می‌کند. به گونه‌ای که این دستورالعمل‌ها به هویت Thread‌ی فعلی سیستم‌عامل فیزیکی بستگی دارند.
6
public static void EndCriticalRegion()
یک میزبان را قبل از ورود فرآیند اجرا به منطقه‌ی کدها مطلع می‌کند. به گونه‌ای که در این کد اثرات لغو شدن یک Thread و یا یک استثنای کنترل نشده محدود به کار فعلی هستند.
7
public static void EndThreadAffinity()
یک میزبان را از اتمام اجرای دستورالعمل توسط کد مدیریت‌شده مطلع می‌کند. به گونه‌ای که این دستورالعمل‌ها به هویت Thread‌ی فعلی سیستم عامل فیزیکی بستگی دارند.
8
public static void FreeNamedDataSlot(string name)
ارتباط بین یک اسم و یک شیار را برای تمامی Thread‌های موجود در فرآیند حذف می‌کند. برای رسیدن به عملکرد بهتر از فیلدهایی استفاده کنید که با استفاده از صفت ThreadStaticAttribute نشان شده‌اند.
9
public static Object GetData(LocalDataStoreSlot slot)
در Thread‌ی فعلی مقدار را از شیار مشخص شده و داخل دامنه‌ی فعلی این Thread بازیابی می‌کند. برای رسیدن به عملکرد بهتر از فیلدهایی استفاده کنید که با استفاده از صفت ThreadStaticAttribute نشان شده‌اند.
10
public static AppDomain GetDomain()
دامنه‌ی فعلی که Thread‌ی فعلی در حال اجرا در آن است را برگشت می‌دهد.
11
public static AppDomain GetDomainID()
شناسه‌ی یک دامنه‌ی برنامه‌ی منحصر به فرد را برگشت می‌دهد.
12
public static LocalDataStoreSlot GetNamedDataSlot(string name)
به جستجوی یک شیار داده‌ای نام دار می‌پردازد. برای رسیدن به عملکرد بهتر از فیلدهایی استفاده کنید که با استفاده از صفت ThreadStaticAttribute نشان شده‌اند.
13
public void Interrupt()
در Thread‌ای وقفه وارد می‌کند که در حالت WaitSleepJoin قرار دارد.
14
public void Join()
تا زمان اتمام Thread، فراخوانی Thread‌ها را مسدود می‌کند. در عین حال ارسال SendMessage و اجرای COM استاندارد را ادامه می‌دهد. این متد فرم‌های با بار بیش از حد متفاوتی دارد.
15
public static void MemoryBarrier()
به صورت زیر دسترسی حافظه را هماهنگ می‌کند:
پردازنده‌ای که Thread‌ی فعلی را اجرا می‌کند نمی‌تواند ترتیب دستورالعمل‌ها را به هم بزند به گونه‌ای که دسترسی به حافظه قبل از فراخوانی MemoryBarrier بعد از دسترسی به حافظه‌ای اجرا شود که به دنبال فراخوانی MemoryBarrier می‌آید.
16
public static void ResetAbort()
یک درخواست Abort را برای Thread‌ی فعلی لغو می‌کند.
17
public static void SetData(LocalDataStoreSlot slot, Object data)
در شیار مشخص Thread‌ی در حال اجرا داده‌ی مربوط به دامنه‌ی فعلی این Thread را ارسال می‌کند. برای رسیدن به عملکرد بهتر از فیلدهایی استفاده کنید که با استفاده از صفت ThreadStaticAttribute نشان شده‌اند.
18
public void Start()
Thread‌ای را آغاز می‌کند.
19
public static void Sleep(int millisecondsTimeout)
برای مدت زمانی Thread را متوقف می‌کند.
20
public static void SpinWait(int iterations)
باعث می‌شود یک Thread برای دفعاتی که توسط پارامتر تکرار تعریف می‌شود به حالت انتظار برود.
21
public static byte VolatileRead(ref byte address)
public static double VolatileRead(ref double address)
public static int VolatileRead(ref int address)
public static Object VolatileRead(ref Object address)
مقدار یک فیلد را می‌خواند. این مقدار آخرین مقداری است که توسط تمامی پردازشگرهای یک کامپیوتر نوشت شده است؛ صرف نظر از تعداد پردازشگرها یا حالت حافظه‌ی cache پردازشگر. این متد حالت‌های با بار بیش از حد مختلفی دارد. تنها بخشی از آن‌ها در بالا بیان شده‌اند.
22
public static void VolatileWrite(ref byte address,byte value)
public static void VolatileWrite(ref double address, double value)
public static void VolatileWrite(ref int address, int value)
public static void VolatileWrite(ref Object address, Object value)
بلافاصله مقداری را برای یک فیلد می‌نویسد به گونه‌ای که تمام پردازشگرهای کامپیوتر بتوانند این مقدار را ببینند. این متد حالت‌های با بار بیش از حد مختلفی دارد. تنها بخشی از آن‌ها در بالا بیان شده‌اند.
23
public static bool Yield()
باعث می‌شود فراخوانی Thread منجر به اجرای Thread‌ی دیگری شود که در پردازشگر فعلی آماده‌ی اجرا شدن است. سیستم عامل Thread‌ی آماده به اجرا را انتخاب می‌کند.

ایجاد Thread‌ها

Thread‌ها را می‌توان با بسط دادن کلاس Thread ایجاد کرد. بعد از این کار این کلاس جهت آغاز اجرای Thread‌ی فرزند متد Start() را فراخوانی می‌کند.

در برنامه‌ی زیر این مفهوم نشان داده شده است:

using System;
using System.Threading;
namespace MultithreadingApplication {
 class ThreadCreationProgram {
 public static void CallToChildThread() {
 Console.WriteLine("Child thread starts");
 }
 static void Main(string[] args) {
 ThreadStart childref = new ThreadStart(CallToChildThread);
 Console.WriteLine("In Main: Creating the Child thread");
 Thread childThread = new Thread(childref);
 childThread.Start();
 Console.ReadKey();
 }
 }
}

زمانی که کد بالا کامپایل و اجرا شود، نتیجه به صورت زیر نمایش داده می‌شود:

In Main: Creating the Child thread
Child thread starts

مدیریت Thread‌ها

کلاس Thread متدهای مختلفی را فراهم می‌کند که به کمک آن‌ها می‌توان Thread‌ها را مدیریت کرد.
در مثال زیر کاربرد متد sleep() جهت توقف یک Thread برای زمان مشخص نشان داده شده است.

using System;
using System.Threading;
namespace MultithreadingApplication {
 class ThreadCreationProgram {
 public static void CallToChildThread() {
 Console.WriteLine("Child thread starts");
         
// the thread is paused for 5000 milliseconds
 int sleepfor = 5000;
         
 Console.WriteLine("Child Thread Paused for {0} seconds", sleepfor / 1000);
 Thread.Sleep(sleepfor);
 Console.WriteLine("Child thread resumes");
 }
      
 static void Main(string[] args) {
 ThreadStart childref = new ThreadStart(CallToChildThread);
 Console.WriteLine("In Main: Creating the Child thread");
         
 Thread childThread = new Thread(childref);
 childThread.Start();
 Console.ReadKey();
 }
 }
}

زمانی که کد بالا کامپایل و اجرا می‌شود، نتیجه به صورت زیر نمایش داده می‌شود:

In Main: Creating the Child thread
Child thread starts
Child Thread Paused for 5 seconds
Child thread resumes

از بین بردن Thread‌

جهت از بین بردن Thread‌ها باید از متد Abort() استفاده کنید.

زمان اجرا با throw کردن یک ThreadAbortException Thread را به صورت نیمه‌کاره متوقف می‌کند. با توجه با اینکه نمی‌توان متوجه این استثنا شد، کنترل به بلوک نهایی ارسال می‌شود، البته اگر وجود داشته باشد.
در برنامه زیر این مطلب نشان داده شده است:

using System;
using System.Threading;
namespace MultithreadingApplication {
 class ThreadCreationProgram {
 public static void CallToChildThread() {
 try {
 Console.WriteLine("Child thread starts");
            
// do some work, like counting to 10
 for (int counter = 0; counter <= 10; counter++) {
 Thread.Sleep(500);
 Console.WriteLine(counter);
 }
            
 Console.WriteLine("Child Thread Completed");
 } catch (ThreadAbortException e) {
 Console.WriteLine("Thread Abort Exception");
 } finally {
 Console.WriteLine("Couldn't catch the Thread Exception");
 }
 }
 static void Main(string[] args) {
 ThreadStart childref = new ThreadStart(CallToChildThread);
 Console.WriteLine("In Main: Creating the Child thread");
         
 Thread childThread = new Thread(childref);
 childThread.Start();
         
//stop the main thread for some time
 Thread.Sleep(2000);
         
//now abort the child
 Console.WriteLine("In Main: Aborting the Child thread");
         
 childThread.Abort();
 Console.ReadKey();
 }
 }
}

زمانی که کد بالا کامپایل و اجرا شود، نتیجه به صورت زیر نمایش داده می‌شود:

In Main: Creating the Child thread
Child thread starts
0
1
2
In Main: Aborting the Child thread
Thread Abort Exception
Couldn't catch the Thread Exception

  • 253
  •    260
  • تاریخ ارسال :   1397/08/26

دانلود PDF دانشجویان گرامی اگر این مطلب برای شما مفید بود لطفا ما را در GooglePlus محبوب کنید
رمز عبور: tahlildadeh.com یا www.tahlildadeh.com
ارسال دیدگاه نظرات کاربران
شماره موبایل دیدگاه
عنوان پست الکترونیک

ارسال

آموزشگاه برنامه نویسی تحلیل داده
آموزشگاه برنامه نویسی تحلیل داده

تمامی حقوق این سایت متعلق به آموزشگاه تحلیل داده می باشد .