سؤال

عند كتابة تطبيقات متعددة الخيوط، فإن إحدى المشكلات الأكثر شيوعًا التي تواجهها هي الجمود.

أسئلتي للمجتمع هي:

  1. ما هو الطريق المسدود؟

  2. كيف تكتشفهم؟

  3. هل تتعامل معهم؟

  4. وأخيرًا، كيف يمكنك منع حدوثها؟

هل كانت مفيدة؟

المحلول

أ قفل يحدث عندما تحاول عمليات متعددة الوصول إلى نفس المورد في نفس الوقت.

تخسر إحدى العمليات ويجب أن تنتظر حتى تنتهي الأخرى.

أ طريق مسدود يحدث عندما لا تزال عملية الانتظار متمسكة بمورد آخر يحتاجه الأول قبل أن يتمكن من الانتهاء.

إذن مثال:

يتم استخدام المورد أ والمورد ب بواسطة العملية X والعملية Y

  • يبدأ X في استخدام A.
  • يحاول X وY البدء باستخدام B
  • Y "يفوز" ويحصل على B أولاً
  • الآن Y يحتاج إلى استخدام A
  • A مقفل بواسطة X، الذي ينتظر Y

أفضل طريقة لتجنب حالة الجمود هي تجنب تقاطع العمليات بهذه الطريقة.قلل من الحاجة إلى قفل أي شيء بقدر ما تستطيع.

في قواعد البيانات، تجنب إجراء الكثير من التغييرات على جداول مختلفة في معاملة واحدة، وتجنب المشغلات وقم بالتبديل إلى القراءات المتفائلة/القذرة/nolock قدر الإمكان.

نصائح أخرى

اسمحوا لي أن أشرح مثالاً حقيقيًا (ليس حقيقيًا في الواقع) لحالة الجمود من أفلام الجريمة.تخيل أن مجرمًا يحتجز رهينة، وفي مقابل ذلك، يحتجز الشرطي أيضًا رهينة وهو صديق للمجرم.في هذه الحالة، لن يسمح المجرم للرهينة بالذهاب إذا لم يسمح الشرطي لصديقه بالذهاب.كما أن الشرطي لن يسمح لصديق المجرم بالرحيل إلا إذا أطلق المجرم سراح الرهينة.وهذا وضع لا نهاية له وغير جدير بالثقة، لأن كلا الجانبين يصران على الخطوة الأولى من بعضهما البعض.

المشهد الجنائي والشرطي

enter image description here

لذلك ببساطة، عندما يحتاج خيطان إلى موردين مختلفين ولكل منهما قفل المورد الذي يحتاجه الآخر، فهذا طريق مسدود.

تفسير آخر رفيع المستوى للمأزق:قلوب مكسورة

أنت تواعد فتاة، وبعد يوم واحد من الشجار، ينفطر قلب كلا الطرفين تجاه بعضهما البعض وينتظران موعدًا أنا-آسفة-و-افتقدتك يتصل.في هذه الحالة، يرغب كلا الجانبين في التواصل مع بعضهما البعض فقط إذا تلقى أحدهما رسالة أنا آسف مكالمة من الاخر .نظرًا لأن أيًا منهما لن يبدأ الاتصال والانتظار في حالة سلبية، فإن كلاهما سينتظر الآخر لبدء الاتصال الذي ينتهي في حالة توقف تام.

لن تحدث حالات الجمود إلا عندما يكون لديك قفلان أو أكثر يمكن الحصول عليهما في نفس الوقت ويتم الإمساك بهما بترتيب مختلف.

طرق تجنب الوقوع في طريق مسدود هي:

  • تجنب وجود الأقفال (إن أمكن)،
  • تجنب وجود أكثر من قفل واحد
  • خذ دائمًا الأقفال بنفس الترتيب.

لتحديد حالة الجمود، أولاً سأقوم بتعريف العملية.

عملية : كما نعلم العملية ليست سوى program في التنفيذ.

الموارد : لتنفيذ عملية البرنامج يحتاج إلى بعض الموارد.قد تتضمن فئات الموارد الذاكرة والطابعات ووحدات المعالجة المركزية والملفات المفتوحة ومحركات الأشرطة والأقراص المضغوطة وما إلى ذلك.

طريق مسدود : الجمود هو موقف أو حالة عندما تحتجز عمليتان أو أكثر بعض الموارد وتحاولان الحصول على المزيد من الموارد، ولا يمكنهما تحرير الموارد حتى تنتهي من التنفيذ هناك.

حالة الجمود أو الوضع

enter image description here

في الرسم البياني أعلاه هناك عمليتان ص1 و ص2 وهناك نوعان من الموارد ر1 و R2.

الموارد ر1 يتم تخصيصها للعملية ص1 والموارد R2 يتم تخصيصها للعملية ص2.لاستكمال تنفيذ العملية ص1 يحتاج إلى الموارد R2, ، لذا ص1 طلب ل R2, ، لكن R2 تم تخصيصها بالفعل ل ص2.

بنفس الطريقة العملية ص2 لاستكمال احتياجاته التنفيذية ر1, ، لكن ر1 تم تخصيصها بالفعل ل ص1.

لا يمكن لكلتا العمليتين تحرير مواردهما حتى تكتمل عملية التنفيذ.لذا فإن كلاهما ينتظر موارد أخرى وسينتظران إلى الأبد.لذلك هذا هو طريق مسدود حالة.

لكي يحدث الجمود، يجب أن تتوفر أربعة شروط.

  1. استبعاد متبادل - يتم تخصيص كل مورد حاليًا لعملية واحدة بالضبط أو يكون متاحًا.(لا يمكن لعمليتين التحكم في نفس المورد في وقت واحد أو يكون في قسمهما الحرج).
  2. عقد وانتظر - يمكن للعمليات التي تحتفظ بالموارد حاليًا أن تطلب موارد جديدة.
  3. لا الشفعة - بمجرد أن تحتفظ العملية بمورد، لا يمكن أن يتم إزالته بواسطة عملية أخرى أو النواة.
  4. الانتظار الدائري - كل عملية تنتظر الحصول على مورد تحتفظ به عملية أخرى.

ويتم استيفاء كل هذه الشروط في الرسم البياني أعلاه.

يحدث الجمود عندما ينتظر الخيط شيئًا لا يحدث أبدًا.

عادةً ما يحدث ذلك عندما يكون الخيط في انتظار كائن المزامنة (mutex) أو الإشارة المرورية التي لم يحررها المالك السابق مطلقًا.

يحدث هذا أيضًا بشكل متكرر عندما يكون لديك موقف يتضمن خيطين وقفلين مثل هذا:

Thread 1               Thread 2

Lock1->Lock();         Lock2->Lock();
WaitForLock2();        WaitForLock1();   <-- Oops!

يتم اكتشافها بشكل عام لأن الأشياء التي تتوقع حدوثها لا تحدث أبدًا، أو أن التطبيق يتوقف تمامًا.

يمكنك إلقاء نظرة على هذا مقالات رائعة, ، تحت القسم طريق مسدود.إنه في C# ولكن الفكرة لا تزال هي نفسها بالنسبة للأنظمة الأساسية الأخرى.وأقتبس هنا لسهولة القراءة

يحدث Deadlock عندما ينتظر كل منهما موضوعًا لمورد يحتفظ به الآخر ، لذلك لا يمكن المضي قدمًا.أسهل طريقة لتوضيح ذلك مع قفلان:

object locker1 = new object();
object locker2 = new object();

new Thread (() => {
                    lock (locker1)
                    {
                      Thread.Sleep (1000);
                      lock (locker2);      // Deadlock
                    }
                  }).Start();
lock (locker2)
{
  Thread.Sleep (1000);
  lock (locker1);                          // Deadlock
}

يعد الجمود مشكلة شائعة في مشكلات المعالجة المتعددة/البرمجة المتعددة في نظام التشغيل.لنفترض أن هناك عمليتين P1 وP2 واثنين من الموارد القابلة للمشاركة عالميًا R1 وR2 وفي القسم الحرج يجب الوصول إلى كلا الموردين

في البداية، يقوم نظام التشغيل بتعيين R1 لمعالجة P1 وR2 لمعالجة P2.نظرًا لأن كلا العمليتين تعملان بشكل متزامن، فقد يبدأان في تنفيذ التعليمات البرمجية الخاصة بهما ولكن المشكلة تنشأ عندما تصل العملية إلى القسم الحرج.لذا ستنتظر العملية R1 حتى تقوم العملية P2 بتحرير R2 والعكس صحيح...لذلك سوف ينتظرون إلى الأبد (حالة الجمود).

تشبيه صغير...

والدتك (نظام التشغيل)،
أنت (P1)،
أخوك (P2)،
أبل (R1)،
سكين (R2)،
القسم الحرج (قطع التفاح بالسكين).

تعطيك والدتك التفاحة والسكين لأخيك في البداية.
كلاهما سعيد ويلعب (ينفذان أكوادهما).
أي شخص منكم يريد قطع التفاحة (القسم الحرج) في مرحلة ما.
أنت لا تريد أن تعطي التفاحة لأخيك.
أخوك لا يريد أن يعطيك السكين.
لذلك سوف ينتظر كلاكما لفترة طويلة جدًا :)

يحدث الجمود عندما تكون هناك سلسلة دائرية من الخيوط أو العمليات التي تحتوي كل منها على مورد مقفل وتحاول قفل المورد الذي يحتفظ به العنصر التالي في السلسلة.على سبيل المثال، هناك خيطان يحملان القفل A والقفل B على التوالي، وكلاهما يحاول الحصول على القفل الآخر.

يحدث الجمود عندما يحصل خيطان على أقفال تمنع أي منهما من التقدم.أفضل طريقة لتجنبها هي التطوير الدقيق.تحمي العديد من الأنظمة المدمجة منها باستخدام مؤقت المراقبة (مؤقت يقوم بإعادة ضبط النظام عندما يتم تعليقه لفترة زمنية معينة).

الجمود هو حالة نظام لا تستطيع فيها أي عملية/خيط واحد تنفيذ إجراء ما.كما ذكر آخرون، عادةً ما يكون الجمود نتيجة لموقف ترغب فيه كل عملية/سلسلة رسائل في الحصول على قفل لمورد مقفل بالفعل بواسطة عملية/سلسلة رسائل أخرى (أو حتى نفس الشيء).

هناك طرق مختلفة للعثور عليهم وتجنبهم.المرء يفكر بجد و/أو يحاول الكثير من الأشياء.ومع ذلك، فإن التعامل مع التوازي أمر بالغ الصعوبة ولن يتمكن معظم الأشخاص (إن لم يكن جميعهم) من تجنب المشاكل تمامًا.

قد تكون بعض الطرق الرسمية مفيدة إذا كنت جادًا في التعامل مع هذه الأنواع من المشكلات.الطريقة الأكثر عملية التي أعرفها هي استخدام المنهج النظري للعملية.هنا تقوم بتصميم نظامك ببعض لغات المعالجة (على سبيل المثال.CCS، CSP، ACP، mCRL2، LOTOS) واستخدم الأدوات المتاحة للتحقق (النموذج-) من حالة الجمود (وربما بعض الخصائص الأخرى أيضًا).ومن أمثلة مجموعة الأدوات المستخدمة FDR، وmCRL2، وCADP، وUppaal.قد تثبت بعض النفوس الشجاعة أن أنظمتها خالية من الجمود باستخدام أساليب رمزية بحتة (إثبات النظرية؛ابحث عن Owicki-Gries).

ومع ذلك، فإن هذه الأساليب الرسمية تتطلب عادة بعض الجهد (على سبيل المثال.تعلم أساسيات نظرية العملية).لكنني أعتقد أن هذا مجرد نتيجة لحقيقة أن هذه المشاكل صعبة.

الجمود هو موقف يحدث عندما يكون هناك عدد أقل من الموارد المتاحة كما هو مطلوب من خلال عملية مختلفة.يعني أنه عندما يصبح عدد الموارد المتاحة أقل مما يطلبه المستخدم، في ذلك الوقت تصبح العملية في حالة انتظار. وفي بعض الأحيان يزيد الانتظار أكثر ولا توجد أي فرصة للتحقق من مشكلة نقص الموارد بعد ذلك يُعرف هذا الوضع باسم الجمود.في الواقع، يعد الجمود مشكلة كبيرة بالنسبة لنا ويحدث فقط في نظام التشغيل متعدد المهام. لا يمكن أن يحدث الجمود في نظام التشغيل ذو المهمة الواحدة لأن جميع الموارد موجودة فقط لتلك المهمة قيد التشغيل حاليًا......

فوق بعض التفسيرات لطيفة.نأمل أن يكون هذا مفيدًا أيضًا:https://ora-data.blogspot.in/2017/04/deadlock-in-Oracle.html

في قاعدة البيانات، عندما تكون الجلسة (على سبيل المثال.ora) يريد موردًا تحتفظ به جلسة أخرى (على سبيل المثال.data)، لكن تلك الجلسة (البيانات) تريد أيضًا موردًا تحتفظ به الجلسة الأولى (ora).يمكن أن يكون هناك أكثر من جلستين أيضًا ولكن الفكرة ستكون نفسها.في الواقع، تمنع حالة التوقف التام بعض المعاملات من الاستمرار في العمل.على سبيل المثال:لنفترض أن Ora-data تحمل القفل A ويطلب القفل B و SKU يحمل القفل B ويطلب Lock A.

شكرًا،

يحدث حالة توقف تام عندما ينتظر الخيط انتهاء الخيط الآخر، والعكس صحيح.

كيفية تجنب؟
- تجنب الأقفال المتداخلة
- تجنب الأقفال غير الضرورية
- استخدام موضوع الانضمام ()

كيف تكتشف ذلك؟
قم بتشغيل هذا الأمر في كمد:

jcmd $PID Thread.print

مرجع :geeksforgeeks

برنامج كلاسيكي وبسيط للغاية للفهم طريق مسدود الموقف :-

public class Lazy {

    private static boolean initialized = false;

    static {
        Thread t = new Thread(new Runnable() {
            public void run() {
                initialized = true;
            }
        });

        t.start();

        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        System.out.println(initialized);
    }
}

عندما يستدعي الخيط الرئيسي lazy.main ، فإنه يتحقق مما إذا كان قد تمت تهيئة الفئة كسول ويبدأ في تهيئة الفصل.يتم تعيين مؤشر الترابط الرئيسي الآن تهيئته إلى FALSE ، ويقوم بإنشاء ويبدأ مؤشر ترابط الخلفية الذي تم تهيئة طريقة تشغيله إلى TRUE ، وينتظر إكمال مؤشر ترابط الخلفية.

هذه المرة، تتم حاليًا تهيئة الفصل بواسطة مؤشر ترابط آخر.في ظل هذه الظروف ، ينتظر مؤشر الترابط الحالي ، وهو مؤشر ترابط الخلفية ، على كائن الفئة حتى يكتمل التهيئة.لسوء الحظ ، فإن الخيط الذي يقوم بالتهيئة ، الخيط الرئيسي ، ينتظر إكمال مؤشر ترابط الخلفية.لأن الخيطين ينتظران الآن بعضهما البعض ، والبرنامج هو طريق مسدود.

مشكلة الجمود

  • أقدم أنظمة تشغيل الكمبيوتر تدير برنامجًا واحدًا فقط في وقت واحد
  • كانت جميع موارد النظام متاحة لهذا البرنامج
  • في وقت لاحق ، تدير أنظمة التشغيل برامج متعددة في وقت واحد ، وتراجعها
  • كانت البرامج مطلوبة لتحديد مسبقًا الموارد التي يحتاجون إليها حتى يتمكنوا من تجنب النزاعات مع البرامج الأخرى التي تعمل في نفس الوقت
  • في نهاية المطاف، قدمت بعض أنظمة التشغيل تخصيصًا ديناميكيًا للموارد
  • يمكن أن تطلب البرامج مخصصات إضافية للموارد بعد أن بدأوا في الترشح
  • وهذا أدى إلى مشكلة الجمود

مجموعة من العمليات المحظورة لكل منها مورد وينتظر الحصول على مورد تحتفظ به عملية أخرى في المجموعة

الموقف الذي ينتهي فيه كل من الإجراءات المتنافسة 02 أو أكثر ، وبالتالي لا يفعل ذلك أبدًا

توصيف الجمود

  • استبعاد متبادل
  • عقد وانتظر
  • لا الشفعة
  • الانتظار الدائري

طرق التعامل مع الجمود

  • تأكد من أن النظام لن يدخل أبدًا في حالة توقف تام
  • اسمح للنظام بدخول حالة تميت إلى طريق التعافي
  • تجاهل المشكلة والتظاهر بأن مسدود لا تحدث في النظام ؛تستخدمها معظم أنظمة التشغيل ، بما في ذلك UNIX

الوقاية من الطريق المسدود

  • استبعاد متبادل - غير مطلوبة للموارد القابلة للمشاركة؛يجب الاحتفاظ بالموارد غير القابلة للمشاركة

  • عقد وانتظر - يجب أن تضمن أنه كلما طلبت العملية مورد ما ، فإنها لا تحمل أي موارد أخرى

  • لا الشفعة - إذا كانت عملية تعقد بعض طلبات الموارد مورد آخر لا يمكن تخصيصه على الفور ، يتم إصدار جميع الموارد التي يتم الاحتفاظ بها حاليًا

  • الانتظار الدائري - فرض ترتيب إجمالي لجميع أنواع الموارد ، ويتطلب أن تطلب كل عملية الموارد بترتيب متزايد للتعداد

Mutex في جوهره هو قفل يوفر الوصول المحمي إلى الموارد المشتركة.في نظام Linux، نوع بيانات كائن المزامنة لمؤشر الترابط هو pthread_mutex_t.قبل الاستخدام، قم بتهيئته.

للوصول إلى الموارد المشتركة، عليك تأمين كائن المزامنة (mutex).إذا كان كائن المزامنة موجودًا بالفعل على القفل، فسيقوم الاستدعاء بحظر الخيط حتى يتم إلغاء قفل كائن المزامنة.عند الانتهاء من زيارة الموارد المشتركة، يجب عليك فتحها.

بشكل عام، هناك بعض المبادئ الأساسية غير المكتوبة:

  • احصل على القفل قبل استخدام الموارد المشتركة.

  • عقد القفل لأقصر وقت ممكن.

  • قم بتحرير القفل إذا قام الخيط بإرجاع خطأ.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top