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

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

ضع في اعتبارك فئة نرغب فيها في أساليب StartUpdate و CheckAndUpdate و Stop ، يتم استخدام C ++ والرمز بسيط قدر الإمكان:
std::recursive_mutex m_mutex; Future m_future; void Stop() { std::unique_lock scoped_lock(m_mutex); m_future.Wait();
ما يجب الانتباه إليه في الكود المقدم:
- يستخدم mutex العودية. لا يؤدي الالتقاط المتكرر لـ mutex متكرر إلى توقع فقط في حالة حدوث هذه الالتقاط في نفس مؤشر الترابط. في هذه الحالة ، يجب أن يتطابق عدد إعفاءات mutex مع عدد الأسرى. إذا حاولنا التقاط كائن مزامنة متكرر تم التقاطه بالفعل في خيط آخر ، فسيذهب الخيط إلى وضع الاستعداد.
- تبدأ دالة Future :: Schedule (بالمللي ثانية) في مؤشر ترابط منفصل تم تمرير رد الاتصال إليه
نحلل الآن جميع المعلومات الواردة ونقوم بتكوين صورة:

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