JavaRush /مدونة جافا /Random-AR /ما هو الفرق بين كائن المزامنة (mutex) والشاشة والإشارة؟

ما هو الفرق بين كائن المزامنة (mutex) والشاشة والإشارة؟

نشرت في المجموعة
مرحبًا! أثناء دراسة تعدد مؤشرات الترابط في JavaRush، كثيرًا ما صادفت مفاهيم "mutex" و"monitor". هل يمكنك الآن، دون إلقاء نظرة خاطفة، الإجابة على مدى اختلافهما؟ :) ما هو الفرق بين كائن المزامنة والشاشة والإشارة - 1إذا استطعت، أحسنت! إذا لم يكن الأمر كذلك (ويحدث هذا غالبًا) - فلا عجب. إن مفهومي "mutex" و"الشاشة" مرتبطان بالفعل. علاوة على ذلك، أثناء قراءة المحاضرات ومشاهدة مقاطع الفيديو حول تعدد مؤشرات الترابط على الموارد الخارجية على الإنترنت، سوف تصادف مفهومًا آخر مشابهًا - "الإشارة". وظيفتها أيضًا تشبه إلى حد كبير الشاشة وكائن المزامنة (mutex). لذلك، دعونا نفهم هذه المصطلحات الثلاثة، وننظر إلى بعض الأمثلة وننظم أخيرًا في رؤوسنا فهم مدى اختلافها عن بعضها البعض :)

موتيكس

كائن المزامنة (mutex) هو كائن خاص لمزامنة سلاسل الرسائل. إنه "مرتبط" بكل كائن في Java - أنت تعرف ذلك بالفعل :) لا يهم ما إذا كنت تستخدم الفئات القياسية أو أنشأت فئاتك الخاصة، على سبيل المثال، Catو Dog: جميع الكائنات من جميع الفئات لها كائن المزامنة (mutex) . يأتي اسم "mutex" من الكلمة الإنجليزية "MUTual Exclusion" - "الاستبعاد المتبادل"، وهذا يعكس الغرض منه تمامًا. كما قلنا في إحدى المحاضرات السابقة، فإن مهمة كائن المزامنة (mutex) هي توفير مثل هذه الآلية بحيث يتمكن مؤشر ترابط واحد فقط من الوصول إلى كائن ما في وقت معين . التشبيه الشائع لكائن المزامنة في الحياة الواقعية هو "مثال المرحاض". عندما يدخل الإنسان إلى المرحاض، فإنه يقفل الباب من الداخل. يعمل المرحاض ككائن يمكن الوصول إليه عن طريق خيوط متعددة. القفل الموجود على باب المرحاض هو دور كائن المزامنة (mutex)، وطابور الأشخاص بالخارج هو دور الخيوط. القفل الموجود على الباب هو عبارة عن مرحاض: فهو يضمن تواجد شخص واحد فقط بالداخل في كل مرة. ما هو الفرق بين كائن المزامنة والشاشة والإشارة - 2بمعنى آخر، يمكن لمؤشر ترابط واحد فقط في كل مرة العمل على الموارد المشتركة. ستفشل محاولات المواضيع الأخرى (الأشخاص) للوصول إلى الموارد المشغولة. يحتوي كائن المزامنة (mutex) على العديد من الميزات المهمة. أولاً ، هناك حالتان فقط ممكنتان - "مجاني" و"مشغول". وهذا يجعل من السهل فهم كيفية عمله: يمكن رسم المتوازيات باستخدام المتغيرات المنطقية صحيح/خطأ أو نظام الأرقام الثنائية 1/0. ثانياً ، لا يمكن السيطرة على الدول بشكل مباشر. لا توجد آليات في Java تسمح لك بأخذ كائن بشكل صريح والحصول على كائن المزامنة (mutex) الخاص به وتعيين الحالة المطلوبة له. بمعنى آخر، لا يمكنك فعل شيء مثل:
Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
وبالتالي، لا يمكن تحرير كائن المزامنة (mutex) للكائن. فقط جهاز Java لديه حق الوصول المباشر إليه. يعمل المبرمجون مع كائنات المزامنة باستخدام أدوات اللغة.

شاشة

الشاشة عبارة عن "وظيفة إضافية" إضافية لكائن المزامنة (mutex). في الواقع، الشاشة عبارة عن قطعة من التعليمات البرمجية "غير مرئية" للمبرمج . بالحديث عن كائن المزامنة (mutex) سابقًا، قدمنا ​​مثالًا بسيطًا:
public class Main {

   private Object obj = new Object();

   public void doSomething() {

       //...some logic available to all threads

       synchronized (obj) {

           //logic that is only available to one thread at a time
       }
   }
}
في كتلة التعليمات البرمجية المميزة بالكلمة synchronized، يتم التقاط كائن المزامنة (mutex) الخاص بالكائن الخاص بنا obj. حسنًا، يحدث الالتقاط، ولكن كيف يتم تحقيق "آلية الدفاع" بالضبط؟ synchronizedلماذا لا يمكن للخيوط الأخرى الدخول داخل الكتلة عندما يرون كلمة ما ؟ إنها الشاشة التي تخلق آلية الحماية! يقوم المترجم بتحويل الكلمة synchronizedإلى عدة أجزاء خاصة من التعليمات البرمجية. لنعود مرة أخرى إلى مثالنا مع الطريقة doSomething()ونضيفها:
public class Main {

   private Object obj = new Object();

   public void doSomething() {

       //...some logic available to all threads

       //logic that is only available to one thread at a time
       synchronized (obj) {

           /*выполнить важную работу, при которой доступ к an objectу
           должен быть только у одного потока*/
           obj.someImportantMethod();
       }
   }
}
إليك ما سيحدث "تحت غطاء" برنامجنا بعد أن يقوم المترجم بتحويل هذا الرمز:
public class Main {

   private Object obj = new Object();

   public void doSomething() throws InterruptedException {

       //...some logic available to all threads

       //логика, которая одновременно доступна только для одного потока:

       /*до тех пор, пока мьютекс an object занят -
       любой другой поток (кроме того, который его захватил), спит*/
       while (obj.getMutex().isBusy()) {
           Thread.sleep(1);
       }

       //пометить мьютекс an object How занятый
       obj.getMutex().isBusy() = true;

       /*выполнить важную работу, при которой доступ к an objectу
       должен быть только у одного потока*/
       obj.someImportantMethod();

       //освободить мьютекс an object
       obj.getMutex().isBusy() = false;
   }
}
والمثال بالطبع ليس حقيقيا. هنا، باستخدام تعليمات برمجية تشبه Java، حاولنا أن نعكس ما يحدث في هذه اللحظة داخل جهاز Java. ومع ذلك، فإن هذا الكود الكاذب يعطي فهمًا كبيرًا لما يحدث بالفعل مع الكائن والخيوط داخل الكتلة synchronizedوكيف يقوم المترجم بتحويل هذه الكلمة إلى عدة أوامر "غير مرئية" للمبرمج. بشكل أساسي، يتم التعبير عن الشاشة في Java باستخدام الكلمةsynchronized . كل الكود الذي ظهر بدلاً من الكلمة synchronizedفي المثال الأخير هو الشاشة.

إشارة

الكلمة الأخرى التي تصادفها عند دراسة تعدد العمليات بمفردك هي "الإشارة". دعونا نتعرف على ما هو وكيف يختلف عن الشاشة وكائن المزامنة (mutex). الإشارة هي وسيلة لمزامنة الوصول إلى المورد. تكمن خصوصيته في أنه يستخدم عدادًا عند إنشاء آلية المزامنة. يخبرنا العداد بعدد سلاسل العمليات التي يمكنها الوصول إلى مورد مشترك في نفس الوقت. ما هو الفرق بين كائن المزامنة والشاشة والإشارة - 3يتم تمثيل الإشارات في Java بواسطة الفصل Semaphore. عند إنشاء كائنات الإشارة، يمكننا استخدام المنشئات التالية:
Semaphore(int permits)
Semaphore(int permits, boolean fair)
نمر إلى المنشئ:
  • int permits- قيمة العداد الأولية والحد الأقصى. بمعنى، كم عدد سلاسل الرسائل التي يمكنها الوصول إلى مورد مشترك في نفس الوقت؛

  • boolean fair- لتحديد الترتيب الذي سيتم من خلاله الوصول إلى المواضيع. إذا كانت fair= true ، فسيتم منح الوصول إلى سلاسل الرسائل المنتظرة بالترتيب الذي طلبته به. إذا كان خطأ ، سيتم تحديد الترتيب من خلال جدولة الموضوع.

أحد الأمثلة الكلاسيكية لاستخدام الإشارات هو مشكلة غداء الفلاسفة .
ما هو الفرق بين كائن المزامنة والشاشة والإشارة - 4
سنقوم بتبسيط مصطلحاته قليلاً لفهم أفضل. تخيل أن لدينا 5 فلاسفة يحتاجون إلى الغداء. وفي الوقت نفسه، لدينا طاولة واحدة، ولا يمكن أن يجلس عليها أكثر من شخصين في نفس الوقت. مهمتنا هي إطعام جميع الفلاسفة. لا ينبغي لأي منهما أن يجوع، ولا ينبغي أن "يعترضا" بعضهما البعض عندما يحاولان الجلوس على الطاولة (يجب علينا تجنب الطريق المسدود). وهذا ما سيبدو عليه صفنا الفيلسوف:
class Philosopher extends Thread {

   private Semaphore sem;

   // поел ли философ
   private boolean full = false;

   private String name;

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

   public void run()
   {
       try
       {
           // если философ еще не ел
           if (!full) {
               //Запрашиваем у семафора разрешение на выполнение
               sem.acquire();
               System.out.println (name + " садится за стол");

               // философ ест
               sleep(300);
               full = true;

               System.out.println (name + " поел! Он выходит из-за стола");
               sem.release();

               // философ ушел, освободив место другим
               sleep(300);
           }
       }
       catch(InterruptedException e) {
           System.out.println ("What-то пошло не так!");
       }
   }
}
وهنا هو الكود لتشغيل برنامجنا:
public class Main {

   public static void main(String[] args) {

       Semaphore sem = new Semaphore(2);
       new Philosopher(sem,"Сократ").start();
       new Philosopher(sem,"Платон").start();
       new Philosopher(sem,"Аристотель").start();
       new Philosopher(sem,"Фалес").start();
       new Philosopher(sem,"Пифагор").start();
   }
}
لقد أنشأنا إشارة ذات عدد 2 لتلبية الشرط القائل بأن اثنين فقط من الفلاسفة يمكنهم تناول الطعام في نفس الوقت. وهذا يعني أنه يمكن لموضوعين فقط العمل في وقت واحد، لأن فصلنا Philosopherموروث من Thread! acquire()تتحكم release()الفصل والأساليب Semaphoreفي عداد الأذونات الخاص به. تطلب الطريقة acquire()إذنًا للوصول إلى مورد من الإشارة. إذا كان العداد > 0، يتم منح الإذن وتقليل العداد بمقدار 1. release()"تحرر" الطريقة الإذن الممنوح مسبقًا وتعيده إلى العداد (زيادة عداد منح الإشارة بمقدار 1). ماذا نحصل عندما نقوم بتشغيل البرنامج؟ فهل تم حل المشكلة، وهل سيتقاتل فلاسفتنا وهم ينتظرون دورهم؟ :) هذا هو مخرج وحدة التحكم الذي تلقيناه: سقراط يجلس على الطاولة، أفلاطون يجلس على الطاولة التي أكلها سقراط! يترك الطاولة وقد أكل أفلاطون! يترك المائدة ويجلس أرسطو على المائدة فيثاغورس يجلس على المائدة التي أكلها أرسطو! يترك المائدة التي أكلها فيثاغورس! يترك الطاولة ويجلس طاليس على الطاولة التي أكلها طاليس! لقد ترك الطاولة لقد نجحنا! وعلى الرغم من أن طاليس كان عليه أن يتناول العشاء بمفرده، إلا أنني أعتقد أنه ليس غاضبًا منا :) ربما لاحظت بعض أوجه التشابه بين كائن المزامنة (mutex) والإشارة المرورية. بشكل عام، لديهم نفس الغرض: مزامنة الوصول إلى بعض الموارد. ما هو الفرق بين كائن المزامنة والشاشة والإشارة - 5والفرق الوحيد هو أنه لا يمكن الحصول على كائن المزامنة (mutex) الخاص بالكائن إلا من خلال مؤشر ترابط واحد في كل مرة، بينما في حالة الإشارة، يتم استخدام عداد الخيوط، ويمكن للعديد منها الوصول إلى المورد في وقت واحد. وهذا ليس مجرد تشابه من قبيل الصدفة :) في الواقع، كائن المزامنة عبارة عن إشارة ذات مكان واحد . أي أنها إشارة تم ضبط عدادها في البداية على 1. وتسمى أيضًا "الإشارة الثنائية" لأن عدادها يمكن أن يحتوي على قيمتين فقط - 1 ("مجاني") و0 ("مشغول"). هذا كل شئ! كما ترون، فقد تبين أن كل شيء لم يكن مربكًا للغاية :) الآن، إذا كنت ترغب في دراسة موضوع تعدد العمليات بمزيد من التفصيل على الإنترنت، فسيكون من الأسهل عليك التنقل بين المفاهيم. نراكم في الدروس القادمة!
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION