همزمان سازی نخ ها یا (Thread Synchronization)
شنبه 30 آبان 1394هماهنگ سازی Thread ها ، مکانیزمی است که در آن چندین Thread که به صورت همزمان اجرا می شوند به یک قسمت از برنامه به صورت همزمان دسترسی نداشته باشند.
هماهنگ سازی Thread ها ، مکانیزمی است که در آن چندین Thread که به صورت همزمان اجرا می شوند به یک قسمت از برنامه به صورت همزمان دسترسی نداشته باشند.
ابتدا پیش زمینه های لازم برای یادگیری بهتر این مقاله را ذکر می کنیم
تعریف Process: Process یک قطعه برنامه در حال اجرا می باشد.یک برنامه مانند یک بازی یا یک سرویس ویا .... می تواند شامل چندین پردازش باشد ولی در اغلب موارد فقط یک پردازش هستند.
Task: فعالیتی است که هم اکنون Cpu در حال انجام ان است و اگر Task Manager را باز کنید لیست پردازش های در حال انجام سیستم را خواهید دید.
Thread:از آنجایی که سرعت انجام پردازش در کامپیوتر بسیار بیشتر از انسان است ، به همین دلیل کامپیوتر قادر به انجام چندین عمل یا Task به صورت همزمان است .پس در واقع هر عملی به چندین عمل کوچک تقسیم شده و هر کدام به عنوان یک Thread در زمان های خالی Cpu اجرا می شوند
از Thread ها برای انجام کارهای موازی و استفاده از وقت تلف شده در بین پردازش ها استفاده می شود.زمانی که یک پردازشی منتظر است که این انتظار می تواند برای عکس العمل کاربر و یا منابع و یا ... باشد در این حالت Thread دیگری که در صف پردازش است انجام می شود و از اتلاف وقت جلوگیری می شود.
بعد از این مقدمات راجع بهThread Synchronization که موضوع اصلی این مقاله است صحبت می کنیم .
برای اینکه چندین Thread به طور همزمان به یک داده دسترسی داشته باشند باید عمل Synchronization انجام شود.اگر این کار در سیستم انجام نشود Thread ها برای دسترسی به آن داده با هم درگیر شده و حالت Deadlock در سیستم اتفاق می افتد.در حالت Deadlock هیچ کدام از پروسه ها نمی توانند منبع را بگیرند.
روش Synchronization روشی است که در آن تمام Thread به صورت مدیریت شده و پشت سر هم به داده مشترک دسترسی دارند.وقتی کار یک Thread با داده یا منبع مشترک تمام شد Thread بعدی که در صف انتظار است به آن دسترسی پیدا می کند.
مشکلاتی که در روش Thread Synchronization وجود دارند در زیر لیست شده اند.به این معنی که هر برنامه ای که چندین Thread دارد باید مشکلات زیر را رفع کرده باشد
The Producer-Consumer
The Readers-Writers
The Dining Philosopher
به اختصار هر کدام از مشکلات بالا را شرح می دهیم .مشکل Producer-Consumer به این معنی است که دو فرآیند به نام ها مصرف کننده و تولید کننده داریم بین اینها یک بافر به اشتراک گذاشته شده است تولید کننده باید داد ه ای را تولید کرده و در بافر قرار دهد و مصرف کننده باید به طور همزمان آن را به مصرف برساند.در این حالت باید کنترل شود که مصرف کننده در بافر پر داده ای قرار ندهد و مصرف کننده هم سعی نکند از بافر خالی اطلاعات بر دارد.
هر وقت بافر پر بود و تولید کننده قصد قرار دادن داده را داشت به خواب برود و همین مسئله برای مصرف کننده هم وجود دارد.
مشکل خوانندگان-نویسندگان به این صورت است که تعدادی Thread به یک ناحیه داده به صورت اشتراکی دسترسی دارند ، تعدادی از Thread فقط می خوانند و تعدادی فقط می نویسند.
مشکل بعدی به نام شام فیلسوف ها یا همان Dining Philosopher نام دارد .دراین مشکل تعداد 5 فیلسوف وجود دارند که دور یک میز گرد در حال شام خوردن هستند .بر روی این میز 5 ظرف ماکارونی و 5 چنگال وجود دارد.فیلسوف ها در حال فکر کردن هستند و یا دارند غذا می خورند تا وقتی هر دو چنگال در دست یک فیلسوف نباشد نمی تواند غذا بخورد .
Thread Synchronization باید قادر به پاسخگویی به مشکلات بالا باشد .البته این روش به تنهایی کاربرد ندارد و مکانیزم های دیگری همراه با آن برای حل مشکلات گفته شده به کار می روند
Thread Synchronization از چهار سناریوی زیر برای رفع مشکل دسترسی به منابع مشترک استفاده می کند
Blocking Methods
Locking Construct
Signaling
No Blocking Synchronization
Blocking Methods
در این تکنیک یک Thread در یک بازه زمانی مشخص و تعریف شده منتظر Thread دیگری می ماند .متدهای مختلفی برای Block شدن وجود دارند از جمله
Sleep
Join
Task.Wait
در روش Sleep پردازش برای یک مدت زمان تعریف شده ای منتظر می ماند .
در طول این زمان CPU در حالت pause قرار دارد.این تکنیک برای external Task یا وظایف خارجی کاربرد دارد
Thread.Sleep(300)
Join
این هم یکی از روش های تکنیک Blocking است .شبیه Sleep است ولی تمام Thread ها را Pause نمی کند . Thread فراخوان را Pause می کند تا زمانی که آن Thread که فراخوانی شده اجرایش تمام شود.
class Program { static void Main(string[] args) { Thread thread1 = new Thread(Method1); thread1.Start(); Thread thread2 = new Thread(Method2); thread2.Start(); thread1.Join(); Console.WriteLine("After Thread1"); thread2.Join(); Console.WriteLine("After Thread2"); Console.ReadKey(); } private static void Method2(object obj) { Console.WriteLine("Thread1 Executed."); } private static void Method1(object obj) { Console.WriteLine("Thread2 Executed"); }
Task.Wait
یک متدی از Task blocking است که که به Thread فراخوان تا زمان کامل شدن Thread جاری ، اجازه Wait شدن می دهد .
class Program { static void Main(string[] args) { Task task = Task.Run(() => { Random randomNumbers = new Random(); long sum = 0; int count = 1000000; for (int i = 1; i <= count; i++) { int randomNumber = randomNumbers.Next(0, 101); sum += randomNumber; } Console.WriteLine("Total:{0}", sum); Console.WriteLine("Count: {0}", count); }); task.Wait(); Console.ReadKey(); } }
Output:
Count: 1000000
سناریوی دوم Locking است
Locking هم اجازه دسترسی کنترل شده به منابع مشترک را می دهد.این سناریو از دو تکنیک زیر استفاده می کند.
Lock
Mutex
روش اول یعنی Lock بخش مشترک را قفل یا Lock می کند .بنابراین در آن واحد تنها یک Thread امکان اجرای این بخش مشترک و یا استفاده از داده های آن را دارد .
class Program { decimal totalBalance =50000; private Object myLock = new Object(); static void Main(string[] args) { Program program = new Program(); program.WithDraw(5000); Console.ReadKey(); } public void WithDraw(decimal amount) { lock (myLock) { if (amount > totalBalance) { Console.WriteLine("Insufficient Amount."); } totalBalance -= amount; Console.WriteLine("Total Balance {0}",totalBalance); } } }
Output:
Total Balance 45000
Mutex
یک نوع خاص متغیر است که توسط سیستم عامل پشتیبانی میشود. وظیفه خاص این متغیر حفاظت از ناحیه بحرانی (ناحیه ای که مشترکا توسط چندین Thread باید به آن دسترسی داشت) است .هر نخی که بخواهد از ناحیه مشترک استفاده کند باید Mutex را قفل کند.در این صورت هیج نخ دیگری نمی تواند از داده مشترک استفاده کند.
- C#.net
- 4k بازدید
- 4 تشکر