أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالمناهج والباقات
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

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

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • المناهج والباقات
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالمناهجالمدونةالدخول
البرمجة بالعربي

الجمود Deadlock: ليه خيطان يستنّيا بعض للأبد وإزاي تمنعه

متوسط٢ يوليو ٢٠٢٦5 دقائق قراءة
الجمود Deadlock: ليه خيطان يستنّيا بعض للأبد وإزاي تمنعه

مستوى المقال: متوسط. الافتراض إنك تعرف يعني إيه thread وقفل (lock) أساسي. لو لسه جديد على الـ threads، المثال الأول في المقال هيوصّلك الفكرة قبل الكود.

في آخر المقال هتعرف تكتشف جمود (deadlock) بيجمّد خدمتك من غير ما يطلع ولا رسالة خطأ، وتصلحه بقاعدة واحدة بسيطة. الوقت المتوقع للقراءة حوالي 7 دقايق.

الجمود (Deadlock): لما خيطان يستنّيا بعض للأبد

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

المشكلة باختصار

تخيّل أخوين في مطبخ. الأول ماسك السكينة ومستني اللوح عشان يقطّع. التاني ماسك اللوح ومستني السكينة. كل واحد مش هيسيب اللي في إيده قبل ما ياخد اللي ناقصه. النتيجة: الاتنين واقفين، والأكل مش هيتعمل. مفيش حد بيصرخ، بس المطبخ متجمّد.

ده بالظبط اللي بيحصل بين الخيوط. القفل هو السكينة أو اللوح. الخيط اللي ماسك قفل ومستني قفل تاني ماسكه خيط بيستنى قفلك انت — ده انتظار دائري (circular wait)، وهو قلب الجمود.

الشرح العلمي: شروط Coffman الأربعة

الجمود مش بيحصل صدفة. في 1971 حدّد Coffman وزملاؤه أربع شروط لازم تتحقق كلها مع بعض عشان يحصل جمود. لو كسرت أي واحدة منهم، الجمود مستحيل:

  1. الإقصاء المتبادل (Mutual Exclusion): المورد مينفعش يتمسك بأكتر من خيط في نفس الوقت. القفل بطبيعته كده.
  2. المسك والانتظار (Hold and Wait): الخيط ماسك مورد وفي نفس الوقت مستني مورد تاني.
  3. عدم النزع (No Preemption): مفيش حد يقدر ياخد القفل من الخيط بالعافية، لازم يسيبه بنفسه.
  4. الانتظار الدائري (Circular Wait): سلسلة خيوط كل واحد مستني اللي بعده، وآخر واحد مستني الأول.

الحل العملي بيهاجم الشرط الرابع، لأنه أسهل واحد تكسره من غير ما تخرّب أداء برنامجك.

نعمله بأيدينا: كود يوريك الجمود

الكود ده بيعمل خيطين، كل واحد بياخد قفلين بترتيب معكوس. حطّينا sleep صغير عشان نضمن إن الجمود يحصل في كل مرة تشغّل:

Python
import threading, time

lock_a = threading.Lock()
lock_b = threading.Lock()

def worker_1():
    with lock_a:
        time.sleep(0.1)
        with lock_b:
            pass

def worker_2():
    with lock_b:
        time.sleep(0.1)
        with lock_a:
            pass

t1 = threading.Thread(target=worker_1)
t2 = threading.Thread(target=worker_2)
t1.start(); t2.start()

t1.join(timeout=3)
t2.join(timeout=3)

if t1.is_alive() or t2.is_alive():
    print("deadlock happened")
else:
    print("done")

لو شغّلته، هيطبع رسالة الجمود. من غير الـ timeout في join كان البرنامج هيقف للأبد. لاحظ: مفيش استثناء، مفيش خطأ. البرنامج شكله شغّال، بس واقف.

الحل: ترتيب أقفال عام (Lock Ordering)

القاعدة بسيطة: خلّي كل الخيوط تاخد الأقفال بنفس الترتيب دائمًا. لو الكل بياخد lock_a قبل lock_b، مستحيل يحصل انتظار دائري.

Python
def worker(first, second):
    with first:
        time.sleep(0.1)
        with second:
            pass

t1 = threading.Thread(target=worker, args=(lock_a, lock_b))
t2 = threading.Thread(target=worker, args=(lock_a, lock_b))
t1.start(); t2.start()
t1.join(); t2.join()
print("no deadlock")

الفرق بالأرقام: النسخة الأولى بتقف عند 3 ثواني (وكانت للأبد). النسخة التانية بتخلّص شغلها الفعلي في أقل من ميلي ثانية بعد الـ sleep. نفس المنطق، نفس الأقفال، بس الترتيب لوحده هو الفرق بين خدمة شغّالة وخدمة ميتة.

سيناريو واقعي: تحويل فلوس بين حسابين

ده مش مثال أكاديمي. تخيّل خدمة تحويل بتخدم 50 ألف عملية في اليوم. كل تحويل بيقفل الحسابين المشتركين. لو عميل بيحوّل من حساب 1 لحساب 2، وفي نفس اللحظة عميل تاني بيحوّل من 2 لـ 1، هيحصل جمود. الخيطين بيتجمدوا، وبعد شوية الـ thread pool بيخلص خيوطه الحرة، وبعدها الخدمة كلها بتقف — مش التحويلين بس. الحل: رتّب القفل حسب رقم الحساب دائمًا:

Python
def transfer(from_acc, to_acc, amount):
    first, second = sorted([from_acc, to_acc], key=lambda a: a.id)
    with first.lock:
        with second.lock:
            from_acc.balance -= amount
            to_acc.balance += amount

دلوقتي الاتنين بياخدوا القفل بنفس الترتيب مهما كان اتجاه التحويل. الانتظار الدائري اتكسر.

الـ trade-offs وحاجات تنتبه لها

  • بتكسب: ضمان عدم حصول جمود، بصفر تكلفة أداء وقت التشغيل.
  • بتخسر: انضباط. كل مكان في الكود بياخد قفلين لازم يحترم نفس الترتيب. لو مبرمج نسي وعكس الترتيب، رجع الجمود.

بديل تاني هو acquire(timeout=1): لو مقدرتش تاخد القفل في ثانية، سيب اللي معاك وحاول تاني. ده بيكسر شرط المسك والانتظار، لكن بتكلفة زمن استجابة أعلى وخطر livelock (الخيوط تفضل تحاول وتتراجع من غير ما تخلّص). الافتراض هنا إن عندك عدد أقفال محدود ومعروف.

متى لا تستخدم هذا

لو خيطك بياخد قفل واحد بس ومش بيعشش أقفال جوه بعضها، الجمود مستحيل أصلًا — متعقّدش الكود بترتيب مالوش لازمة. وكمان لو الداتا بتاعتك صغيرة أو ثابتة (immutable)، فكّر في قفل عام واحد بسيط أو بنية lock-free بدل ما تدير أقفال متعددة.

الخطوة التالية

افتح الكود بتاعك ودوّر على أي مكان بتاخد فيه قفلين مع بعض (with lock1: وجواها with lock2:). اكتب قاعدة ترتيب واحدة مكتوبة (مثلًا: بالاسم أو بالـ id) والتزم بيها في كل المسارات. لو لقيت مكان بياخد الأقفال بترتيب مختلف، ده بالظبط اللي هيجمّدلك السيرفر يوم ما الحِمل يعلى.

المصادر

  • توثيق بايثون الرسمي — threading والـ Lock: docs.python.org/3/library/threading.html
  • E. G. Coffman, M. Elphick, A. Shoshani — System Deadlocks, ACM Computing Surveys, 1971 (الشروط الأربعة للجمود).
  • Wikipedia — Deadlock: en.wikipedia.org/wiki/Deadlock
  • Wikipedia — Dining philosophers problem: en.wikipedia.org/wiki/Dining_philosophers_problem
  • Oracle Java Tutorials — Deadlock: docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة