CodeGym /وبلاگ جاوا /Random-FA /تفاوت بین Mutex، مانیتور و سمافور
John Squirrels
مرحله
San Francisco

تفاوت بین Mutex، مانیتور و سمافور

در گروه منتشر شد
سلام! زمانی که چند رشته‌ای را در CodeGym مطالعه می‌کردید، اغلب با مفاهیم "mutex" و "monitor" روبرو می‌شوید. بدون نگاه کردن، می توانید بگویید چه تفاوتی دارند؟ :) اگر بله، آفرین! اگر نه (این رایج ترین است)، جای تعجب نیست. «Mutex» و «مانیتور» در واقع مفاهیم مرتبط هستند. به‌علاوه، وقتی درس‌ها را می‌خوانید و ویدیوهایی را درباره چند رشته‌ای در وب‌سایت‌های دیگر تماشا می‌کنید، با مفهوم مشابه دیگری مواجه می‌شوید: «سمافور». همچنین عملکرد بسیار مشابهی با مانیتور و mutexes دارد. به همین دلیل قصد داریم این سه اصطلاح را بررسی کنیم. ما به چند مثال نگاه خواهیم کرد و به درک قطعی از تفاوت این مفاهیم با یکدیگر خواهیم رسید :)

موتکس

موتکس (یا قفل) مکانیزم ویژه ای برای همگام سازی نخ ها است. یکی به هر شی در جاوا "ضمیمه" شده است — شما قبلاً این را می‌دانید :) فرقی نمی‌کند که از کلاس‌های استاندارد استفاده می‌کنید یا کلاس‌های خود را ایجاد می‌کنید، به عنوان مثال Cat and Dog : همه اشیاء همه کلاس‌ها یک mutex دارند . اصطلاح "mutex" از "Mutual EXclusion" گرفته شده است که کاملاً هدف آن را توصیف می کند. همانطور که در یکی از درس های قبلی خود گفتیم، mutex این امکان را فراهم می کند که اطمینان حاصل شود که هر بار فقط یک رشته به شی دسترسی دارد. یک مثال محبوب واقعی از موتکس شامل توالت است. وقتی فردی وارد پارتیشن توالت می شود، در را از داخل قفل می کند. توالت مانند یک شی است که با نخ های متعدد می توان به آن دسترسی داشت. قفل در پارتیشن مانند یک موتکس است و صف افراد بیرون نشان دهنده نخ ها است. قفل روی در، موتکس توالت است: تضمین می کند که فقط یک نفر می تواند داخل شود. تفاوت بین موتکس، مانیتور و سمافور چیست؟  - 2به عبارت دیگر، تنها یک رشته در یک زمان می تواند با منابع مشترک کار کند. تلاش سایر رشته ها (افراد) برای دسترسی به منابع اشغال شده با شکست مواجه خواهد شد. یک mutex چندین ویژگی مهم دارد. اول ، فقط دو حالت ممکن است: "قفل" و "قفل". این به ما کمک می کند تا نحوه کار آن را درک کنیم: می توانید با متغیرهای بولی (درست/نادرست) یا اعداد باینری (0/1) موازی ترسیم کنید. دوم ، دولت را نمی توان مستقیماً کنترل کرد. جاوا مکانیزمی ندارد که به شما اجازه دهد صریحاً یک شی را بگیرید، mutex آن را دریافت کنید و وضعیت مورد نظر را تعیین کنید. به عبارت دیگر، شما نمی توانید کاری مانند:
Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
این بدان معنی است که شما نمی توانید mutex یک شی را آزاد کنید. فقط ماشین جاوا دسترسی مستقیم به آن دارد. برنامه نویسان از طریق ابزارهای زبان با mutexe ها کار می کنند.

نظارت کنید

مانیتور یک "روبنا" اضافی بر روی موتکس است. در واقع، مانیتور تکه‌ای از کد است که برای برنامه‌نویس نامرئی است. وقتی قبلاً در مورد mutexe صحبت کردیم، یک مثال ساده آوردیم:
public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...some logic, available for all threads

       synchronized (obj) {

           // Logic available to just one thread at a time
       }
   }
}
در بلوک کد مشخص شده با کلمه کلیدی همگام شده ، mutex شیء obj ما به دست می آید. عالی است، ما می توانیم قفل را بدست آوریم، اما دقیقاً چگونه "محافظت" ارائه می شود؟ وقتی کلمه را همزمان می بینیم ، چه چیزی مانع از ورود رشته های دیگر به بلوک می شود؟ حفاظت از یک مانیتور می آید! کامپایلر کلمه کلیدی هماهنگ شده را به چند قطعه کد خاص تبدیل می کند. یک بار دیگر، اجازه دهید به مثال خود با متد ()doSomething برگردیم . به آن اضافه می کنیم:
public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...some logic, available for all threads

       // Logic available to just one thread at a time
       synchronized (obj) {

           /* Do important work that requires that the object
           be accessed by only one thread */
           obj.someImportantMethod();
       }
   }
}
در اینجا چیزی است که پس از تبدیل این کد توسط کامپایلر "زیر هود" اتفاق می افتد:
public class Main {

   private Object obj = new Object();

   public void doSomething() throws InterruptedException {

       // ...some logic, available for all threads

       // Logic available to just one thread at a time:

       /* as long as the object's mutex is busy,
       all the other threads (except the one that acquired it) are put to sleep */
       while (obj.getMutex().isBusy()) {
           Thread.sleep(1);
       }

       // Mark the object's mutex as busy
       obj.getMutex().isBusy() = true;

       /* Do important work that requires that the object
       be accessed by only one thread */
       obj.someImportantMethod();

       // Free the object's mutex
       obj.getMutex().isBusy() = false;
   }
}
البته این یک مثال واقعی نیست. در اینجا، از کدهای جاوا مانند برای به تصویر کشیدن آنچه در داخل ماشین جاوا اتفاق می افتد استفاده کردیم. گفته شد، این شبه کد درک بسیار خوبی از آنچه در واقع با شی و رشته‌های درون بلوک همگام‌سازی شده اتفاق می‌افتد و اینکه چگونه کامپایلر این کلمه کلیدی را به چندین عبارت که برای برنامه‌نویس نامرئی هستند تبدیل می‌کند، می‌دهد. اساسا، جاوا از کلمه کلیدی همگام سازی شده برای نمایش یک مانیتور استفاده می کند . تمام کدی که به جای کلمه کلیدی همگام سازی شده در مثال آخر ظاهر می شود مانیتور است.

سمافور

کلمه دیگری که در مطالعه شخصی خود در مورد چند رشته ای با آن مواجه خواهید شد، "semaphore" است. بیایید بفهمیم این چیست و چه تفاوتی با مانیتور و موتکس دارد. سمافور ابزاری برای همگام سازی دسترسی به برخی منابع است. ویژگی متمایز آن این است که از یک شمارنده برای ایجاد مکانیسم همگام سازی استفاده می کند. شمارنده به ما می گوید که چند رشته می توانند به طور همزمان به منبع مشترک دسترسی داشته باشند. تفاوت بین موتکس، مانیتور و سمافور چیست؟  - 3سمافورها در جاوا با کلاس Semaphore نمایش داده می شوند . هنگام ایجاد اشیاء سمافور، می توانیم از سازنده های زیر استفاده کنیم:
Semaphore(int permits)
Semaphore(int permits, boolean fair)
موارد زیر را به سازنده منتقل می کنیم:
    int permits - مقدار اولیه و حداکثر شمارنده. به عبارت دیگر، این پارامتر تعیین می کند که چند رشته به طور همزمان می توانند به منبع مشترک دسترسی داشته باشند.
  • Boolean fair - ترتیب دسترسی رشته ها را تعیین می کند. اگر عادلانه درست باشد، آنگاه به رشته‌های منتظر به ترتیبی که درخواست کرده‌اند، دسترسی داده می‌شود. اگر نادرست باشد، ترتیب توسط زمانبندی رشته تعیین می شود.
یک مثال کلاسیک از استفاده از سمافور، مسئله فیلسوف غذاخوری است. تفاوت بین موتکس، مانیتور و سمافور چیست؟  - 4برای تسهیل درک، آن را کمی ساده می کنیم. تصور کنید که ما 5 فیلسوف داریم که باید ناهار بخورند. علاوه بر این، ما یک میز داریم که به طور همزمان نمی تواند بیش از دو نفر را در خود جای دهد. وظیفه ما این است که همه فیلسوفان را تغذیه کنیم. هیچ یک از آنها نباید گرسنه بمانند، و هیچ یک از آنها نباید هنگام نشستن پشت میز یکدیگر را "مسدود" کنند (ما باید از بن بست جلوگیری کنیم). کلاس فیلسوفان ما به این شکل خواهد بود:
class Philosopher extends Thread {

   private Semaphore sem;

   // Did the philosopher eat?
   private boolean full = false;

   private String name;

   Philosopher(Semaphore sem, String name) {
       this.sem=sem;
       this.name=name;
   }

   public void run()
   {
       try
       {
           // If the philosopher has not eaten
           if (!full) {
               // Ask the semaphore for permission to run
               sem.acquire();
               System.out.println(name + " takes a seat at the table");

               // The philosopher eats
               sleep(300);
               full = true;

               System.out.println(name + " has eaten! He leaves the table");
               sem.release();

               // The philosopher leaves, making room for others
               sleep(300);
           }
       }
       catch(InterruptedException e) {
           System.out.println("Something went wrong!");
       }
   }
}
و کد اجرای برنامه ما در اینجا آمده است:
public class Main {

   public static void main(String[] args) {

       Semaphore sem = new Semaphore(2);
       new Philosopher(sem, "Socrates").start();
       new Philosopher(sem,"Plato").start();
       new Philosopher(sem,"Aristotle").start();
       new Philosopher(sem, "Thales").start();
       new Philosopher(sem, "Pythagoras").start();
   }
}
ما یک سمافور ایجاد کردیم که شمارنده آن روی 2 تنظیم شده است تا این شرط را برآورده کند: فقط دو فیلسوف می توانند همزمان غذا بخورند. یعنی فقط دو رشته می توانند همزمان اجرا شوند، زیرا کلاس Philosopher ما Thread را به ارث می برد ! متدهای acquis () و release() کلاس Semaphore شمارنده دسترسی آن را کنترل می کنند. متد ()access از سمافور برای دسترسی به منبع می خواهد. اگر شمارنده > 0 باشد، دسترسی داده می شود و شمارنده به میزان 1 کاهش می یابد . وقتی برنامه را اجرا می کنیم چه چیزی بدست می آوریم؟ آیا مشکل حل شده است؟ آیا فیلسوفان ما در حالی که منتظر نوبت خود هستند نمی جنگند؟ :) در اینجا خروجی کنسولی است که ما دریافت کردیم:

Socrates takes a seat at the table 
Plato takes a seat at the table 
Socrates has eaten! He leaves the table
Plato has eaten! He leaves the table 
Aristotle takes a seat at the table 
Pythagoras takes a seat at the table 
Aristotle has eaten! He leaves the table
Pythagoras has eaten! He leaves the table 
Thales takes a seat at the table 
Thales has eaten! He leaves the table
ما آن را انجام دادیم! و اگرچه تالس مجبور شد به تنهایی ناهار بخورد، من فکر نمی‌کنم ما به او توهین کرده باشیم :) ممکن است متوجه شباهت‌هایی بین موتکس و سمافور شده باشید. در واقع، آنها همان ماموریت را دارند: همگام سازی دسترسی به برخی منابع. تفاوت بین موتکس، مانیتور و سمافور چیست؟  - 5تنها تفاوت این است که mutex یک شی را می توان تنها با یک رشته در یک زمان بدست آورد، در حالی که در مورد سمافور که از یک شمارنده رشته استفاده می کند، چندین رشته می توانند به طور همزمان به منبع دسترسی داشته باشند. این فقط یک تصادف نیست :) یک mutex در واقع یک سمافور با شمارش 1 است. به عبارت دیگر، این سمافوری است که می تواند یک رشته را در خود جای دهد. همچنین به عنوان یک سمافور باینری شناخته می شود زیرا شمارنده آن می تواند تنها 2 مقدار داشته باشد - 1 ("قفل") و 0 ("قفل"). خودشه! همانطور که می بینید، به هر حال آنقدر گیج کننده نیست :) حالا اگر می خواهید چند رشته ای را با جزئیات بیشتری در اینترنت مطالعه کنید، پیمایش این مفاهیم برای شما کمی آسان تر خواهد بود. در درس های بعدی می بینمت!
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION