

در یک سیستم عامل تعداد خیلی زیاد پروسه وجود داره که آماده هستند برای اجرا شدن در یک زمان خاص. این پروسه ها نیازمند منابعی هستند برای اجرا شدن بنابراین این منابع بین این پروسه ها باید تقسیم بشه.
اما یه چیزی هست که باید بهش توجه کنیم اونم اینه که این منابع توزیع شده ولی نباید بصورت همزمان اجرا بشه. مثال عینیش میشه پرینتر،فرض کنید یک پرینتر داریم که برای تمای پروسه ها قابل دسترس هستش ولی فقط یک پروسه میتونه دستور پرینت به پرینتر بفرسته و نمیشه همه با هم بصورت همزمان این کارو انجام بدن و این چیزی هستش که ما بهش میگم Process Synchronization که فارسیش خیلی خوب نمیشه ! ولی شاید بتونیم بگیم هم زمانی پروسه ها.
فرض کنیم که ما ۲ پروسه داریم که هر دو دارن از متغیر a استفاده میکنند، اول متغیر میخوانند و بعدش مقدارشو تغییرش میدن و آخرش دیتایی را داخل مموری ذخیره میکنند.
همونطوری که در فانکشن مشخصه پروسه میاد اول مقدار a میخونه، بعدش مقدارشو با ۵ جمع میکنه و توی خودش ذخیره میکنه و نهایتا توی مموری ذخیرش میکنه.
حالا ما ۲ تا پروسه داریم تحت عنوان P1 و P2 که میخوان اجرا بشن. فرض کنیم مقدار اولیه متغیر a هم ۱۰ هستش.
۱− توی این کیس، پروسه P1 کامل اجرا میشه و بعد از اون پروسه P2 اجرا خواهد شد. بنابراین پروسه P1 اول مقدار a میخونه میبینه ۱۰ هستش بعدش میاد توی فانکشن اونو با ۵ جمعش میکنه میشه ۱۵ میریزه داخل خودش و این مقدار توی مموری آپدیت میشه و حالا مقدار a شده 15.
حالا پروسه دوم P2 میاد میخونه a میبینه ۱۵ هستش با ۵ جمعش میکنه میشه ۲۰ مقدار a آپدیت میشه و نهایتا مقدار a در مموری میشه ۲۰. توی این مثال مقدار نهایی a شد ۲۰.
۲− توی این کیس، بیایم فرض کنیم که پروسه P1 استارت اجراش زده میشه و میاد a میخونه میبینه ۱۰، حالا انتظار داریم بقیه پروسه هم انجام بشه دیگه ولی این وسط یوهو یه اتفاقی می افته اونم Context Switching شاید بپرسین این چه کوفتیه دیگه ! این یه اتفاق جالبیه که توی لایه cpu و kernel اتفاق می افته و اونم اینهه که پروسه یا تسکی که داره اجرا میشه خیلی شیک suspend میشه توسط kernel و روسه بعدی که آماده ی اجرا شدنه توسط cpu فرستاده میشه برای اجرا.
حالا P2 درحال اجرا شدنه و P1 توی حالت Waiting هستش و وضعیت P1 هم ذخیره شده. از اونجایی که پروسه P1 نتونسته مقدار a عوض کنه P2 میره مقدار a میخونه و میبینه که ۱۰ هستش. طبق فانکشن تغییرات اعمال میشه و مقدار a به ۱۵ تغییر پیدا میکنه و توی مموری ذخیره میشه. بعد از اجرای P2 پروسه P1 موقعیتش خونده میشه و از همونجا شروع میکنه به ادامه راه خودش. اگر یادتون باشه a خونده شده بود و الان P1 مقدار a توی خودش ۱۰ داره و میره توی فانکشن و ۵ اضافه میشه و مقدار باز هم میشه ۱۵ و توی این مثال مقدار نهایی a شد ۱۵.
توی این ۲ تا مثال بالا مقدار نهایی اولی شد ۲۰ و دومی شد ۱۵ چه داستانی پشت این میتونه باشه ؟!
پروسه ها دارن از یک ریسورس یکسان استفاده میکنند. متغیر a در روش اول پروسه P1 اجرا شد و بعدش پروسه P2 ولی در روش دوم پروسه P1 متوقف شد و بعد از اجرای پروسه P2 از همونجایی که متوقف شده بود شروع کرد به اجرا شدن. هر دو پروسه هم از منابع یکسانی برخوردار بودن. این critical section پروسه هستش. باید همگام سازی یا synchronization بین پروسه ها وجود داشته باشه وقتیکه دارن از منابع مشترک استفاده میکنند.
منابع مشترک میتونه بین تمامی پروسه ها تقسیم بشه اما فقط یک پروسه اجازه داره در یک زمان از این منابع استفاده کنه. این چیزیه که ما بهش میگیم Process Synchronization
دوتا متد وجود داره برای همگام سازی پروسه ها
1- Mutex
2- Semaphore
خوب تک تک بریم سراغ اینا ببینیم چه کوفتی هستن این دوستان :)
موتکس کارش اینه که به پروسه ها اجازه میده از منابع به شکل یکسان استفاده کنند اما فقط در آن واحد یک پروسه اجازه داره از این منابع استفاده کنه. تکنیکی که موتکس داره استفاده میکنه برای هندل کردن critical section بهش میگن متد Lock-Based
هر زمانیکه یک پروسه از سیستم درخواستی برای منابع داره، سیستم میاد یک آبجکت موتکس میسازه با یک اسم یا آی دی یونیک و هر وقتیکه پروسه بخواد از منابع استفاده کنه پروسه آبجکت قفل میکنه. بعد از پروسه قفل شدن پروسه اجرا میشه کامل و آبجکت موتکس آزاد میکنه. بعد از اون، پروسه دیگه ای اجازه داره که موتکس خودشو بسازه و ازش استفاده کنه.
با استفاده از قفل کردن آبجکت، منبع خاصی که اختصاص داده شده به یک پروسه که هیچ یک از پروسه های دیگه اجازه ندارن از اون منابع استفاده کنند.
خوب با این روش خیلی ساده همگام سازی پروسه ها قابل دسترس هستش.
سمافور یک متغیر عددی به اسم S هستش که مقدار اولیه اون تعداد منابع مصرفی در سیستم برای process synchronization. اون میاد از دو تابع استفاده میکنه برای عوض کردن مقدار S اونم تابع ()wait و ()signal هستش. هر دوی این فانکشن هااستفاده میشن برای تغییر دادن مقدار سمافور اما فقط اجازه میدن یک پروسه تغییر بده مقدار در آن واحد. هر دوی این دو تابع نمیتونن مقدار سمافور در یک زمان با هم تغییر بدن.
دو دسته سمافور وجود داره
Counting Semaphore
Binary Semaphore
در Counting Semaphore اول از همه مقدار اولیه سمافور میشه تعداد منابع قابل دسترس. بعد از اون هروقت یک پروسه نیاز داشته باشه به منابع فانکشن ()wait صدا زده میشهو مقدار سمافور یکی کم میشه.پروسه منابع مصرف میکنه و بعدی فانکشن ()signal صدا زده میشه و مقدار سمافور یکی اضافه میشه ! حالا وقتیکه مقدار سمافور به صفر میرسه تمامی منابع توسط پروسه ها گرفته شدنو هیچ منابعی دیگه وجود نداره برای مصرف. بعد اگر بعضی از پروسه های دیگه بخوان از منابع استفاده کنند اونا ناچار هستند که صبر کنند تا منابع برگرده. با این روش ما خیلی ساده Process Synchronization پیاده سازی کردیم.
در Binary Semaphore مقدار سمافور میشه ۰ یا ۱. در آغاز مقدار متغیر سمافور ست میشه ۱ و اگر بعضی پروسه ها بخوان از منابعی استفاده کنند فانکشن ()wait صدا زده میشه و مقدار سمافور از ۱ به ۰ تغییر پیدا میکنه. بعد از اینکه پروسه کارش تموم میشه فانکشن ()signal صدا زده میشه و مقدار ست میشه ۱ و منابع آزاد میشن. اگر در آن واحد که مقدار متغیر سمافور ۰ هستش بقیه پروسه ها بخوان از منابع استفاده کنندباید صبر کنند که منابع توسط پروسه قبلی آزاد بشه و با این روش باز هم Process Synchronization پیاده سازی میشه. این روش خیلی شبیه موتکس هستش ولی اینجا عمل قفل شدن پیاده سازی نشده.
تا به اینجای کار ما یاد گرفتیم که موتکس و سمافور چی هستن و احتما خیلی ساده تفاوتشونو متوجه شدین محض اطمینان یه جمع بندی کوچولو داشته باشیم بد نیست :) جسارت نباشه ;)