تفاوت بین Mutex و Semaphore در سیستم عامل

منبع

در یک سیستم عامل تعداد خیلی زیاد پروسه وجود داره که آماده هستند برای اجرا شدن در یک زمان خاص. این پروسه ها نیازمند منابعی هستند برای اجرا شدن بنابراین این منابع بین این پروسه ها باید تقسیم بشه.

اما یه چیزی هست که باید بهش توجه کنیم اونم اینه که این منابع توزیع شده ولی نباید بصورت همزمان اجرا بشه. مثال عینیش میشه پرینتر،‌فرض کنید یک پرینتر داریم که برای تمای پروسه ها قابل دسترس هستش ولی فقط یک پروسه میتونه دستور پرینت به پرینتر بفرسته و نمیشه همه با هم بصورت همزمان این کارو انجام بدن و این چیزی هستش که ما بهش میگم Process Synchronization که فارسیش خیلی خوب نمیشه ! ولی شاید بتونیم بگیم هم زمانی پروسه ها.

Process Synchronization and Critical Section

فرض کنیم که ما ۲ پروسه داریم که هر دو دارن از متغیر a استفاده میکنند، اول متغیر میخوانند و بعدش مقدارشو تغییرش میدن و آخرش دیتایی را داخل مموری ذخیره میکنند.

SomeProccess {

....

read(a)

a = a + 5

write(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

خوب تک تک بریم سراغ اینا ببینیم چه کوفتی هستن این دوستان :)

Mutex

موتکس کارش اینه که به پروسه ها اجازه میده از منابع به شکل یکسان استفاده کنند اما فقط در آن واحد یک پروسه اجازه داره از این منابع استفاده کنه. تکنیکی که موتکس داره استفاده میکنه برای هندل کردن critical section بهش میگن متد Lock-Based

هر زمانیکه یک پروسه از سیستم درخواستی برای منابع داره، سیستم میاد یک آبجکت موتکس میسازه با یک اسم یا آی دی یونیک و هر وقتیکه پروسه بخواد از منابع استفاده کنه پروسه آبجکت قفل میکنه. بعد از پروسه قفل شدن پروسه اجرا میشه کامل و آبجکت موتکس آزاد میکنه. بعد از اون، پروسه دیگه ای اجازه داره که موتکس خودشو بسازه و ازش استفاده کنه.

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

خوب با این روش خیلی ساده همگام سازی پروسه ها قابل دسترس هستش.

Semaphore

سمافور یک متغیر عددی به اسم S هستش که مقدار اولیه اون تعداد منابع مصرفی در سیستم برای process synchronization. اون میاد از دو تابع استفاده میکنه برای عوض کردن مقدار S اونم تابع ()wait و ()signal هستش. هر دوی این فانکشن هااستفاده میشن برای تغییر دادن مقدار سمافور اما فقط اجازه میدن یک پروسه تغییر بده مقدار در آن واحد. هر دوی این دو تابع نمیتونن مقدار سمافور در یک زمان با هم تغییر بدن.

دو دسته سمافور وجود داره

Counting Semaphore

Binary Semaphore

در Counting Semaphore اول از همه مقدار اولیه سمافور میشه تعداد منابع قابل دسترس. بعد از اون هروقت یک پروسه نیاز داشته باشه به منابع فانکشن ()wait صدا زده میشهو مقدار سمافور یکی کم میشه.پروسه منابع مصرف میکنه و بعدی فانکشن ()signal صدا زده میشه و مقدار سمافور یکی اضافه میشه ! حالا وقتیکه مقدار سمافور به صفر میرسه تمامی منابع توسط پروسه ها گرفته شدنو هیچ منابعی دیگه وجود نداره برای مصرف. بعد اگر بعضی از پروسه های دیگه بخوان از منابع استفاده کنند اونا ناچار هستند که صبر کنند تا منابع برگرده. با این روش ما خیلی ساده Process Synchronization پیاده سازی کردیم.

در Binary Semaphore مقدار سمافور میشه ۰ یا ۱. در آغاز مقدار متغیر سمافور ست میشه ۱ و اگر بعضی پروسه ها بخوان از منابعی استفاده کنند فانکشن ()wait صدا زده میشه و مقدار سمافور از ۱ به ۰ تغییر پیدا میکنه. بعد از اینکه پروسه کارش تموم میشه فانکشن ()signal صدا زده میشه و مقدار ست میشه ۱ و منابع آزاد میشن. اگر در آن واحد که مقدار متغیر سمافور ۰ هستش بقیه پروسه ها بخوان از منابع استفاده کنندباید صبر کنند که منابع توسط پروسه قبلی آزاد بشه و با این روش باز هم Process Synchronization پیاده سازی میشه. این روش خیلی شبیه موتکس هستش ولی اینجا عمل قفل شدن پیاده سازی نشده.

تفاوت بین موتکس و سمافور

تا به اینجای کار ما یاد گرفتیم که موتکس و سمافور چی هستن و احتما خیلی ساده تفاوتشونو متوجه شدین محض اطمینان یه جمع بندی کوچولو داشته باشیم بد نیست :) جسارت نباشه ;)

  • موتکس مکانیزم قفل شدن استفاده میکنه و اگر پروسه ای بخواد از منابع استفاده کنه اون منابع قفل میکنه، استفاده میشه و بعد آزاد میشه، از اون طرف سمافور میاد از مکانیزم سیگنال استفاده میکنه و متدهای ()wait و ()signal دارن نحوه استفاده از منابع مدیریت میکنند.
  • یک موتکس یک آبجکت هستش اما سمافور یک متغیر از نوع عددی (integer)
  • در سمافور، ما فانکشن های ()wait و ()signal داری، اما در موتکس هیچ فانکشنی وجود نداره برای صدا زدن.
  • یک آبجکت موتکس به چندین تردهای پروسه ها اجازه دسترسی به یک منبع توزیع شده میده اما فقط در یک زمان مشخص و در آن واحد. از اون طرف سمافور به تردهای پروسه ها اجازه دسترسی به instance های محدودی از منابع میده تا وقتیکه در دسترس هستند.
  • در موتکس قفل شدن و آزاد سازی میتونه توسط یک پروسه انجام بشه. اما مقدار سمافور باید آپدیت بشه توسط هر پروسه ای که نیاز داره به منابع اما فقط یک پروسه اجازه داره.