سؤال

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

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

المحلول

العملية غير المنقطعة هي عملية تحدث في استدعاء النظام (وظيفة kernel) ولا يمكن مقاطعتها بواسطة إشارة.

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

أثناء نوم العملية في استدعاء النظام، يمكن أن تتلقى إشارة غير متزامنة لنظام التشغيل Unix (على سبيل المثال، SIGTERM)، ثم يحدث ما يلي:

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

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

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

ركض LWN أ مقال جميل التي تطرقت لهذا الموضوع في يوليو.

للإجابة على السؤال الأصلي:

  • كيفية منع حدوث ذلك:اكتشف برنامج التشغيل الذي يسبب لك المشكلة، وإما أن تتوقف عن استخدامه، أو تصبح مخترقًا لـ kernel وتقوم بإصلاحه.

  • كيفية قتل عملية غير منقطعة دون إعادة التشغيل:بطريقة ما إنهاء مكالمة النظام.غالبًا ما تكون الطريقة الأكثر فعالية للقيام بذلك دون الضغط على مفتاح الطاقة هي سحب سلك الطاقة.يمكنك أيضًا أن تصبح مخترقًا لـ kernel وتجعل برنامج التشغيل يستخدم TASK_KILLABLE، كما هو موضح في مقالة LWN.

نصائح أخرى

عندما تكون العملية في وضع المستخدم، يمكن مقاطعتها في أي وقت (التبديل إلى وضع kernel).عندما تعود النواة إلى وضع المستخدم، فإنها تتحقق مما إذا كانت هناك أية إشارات معلقة (بما في ذلك الإشارات المستخدمة لإيقاف العملية، مثل SIGTERM و SIGKILL).وهذا يعني أنه لا يمكن إنهاء العملية إلا عند العودة إلى وضع المستخدم.

السبب وراء عدم إمكانية قتل العملية في وضع kernel هو أنه من المحتمل أن يؤدي ذلك إلى إتلاف هياكل kernel المستخدمة من قبل جميع العمليات الأخرى في نفس الجهاز (بنفس الطريقة التي يمكن أن يؤدي بها قتل خيط إلى إتلاف هياكل البيانات التي تستخدمها سلاسل رسائل أخرى في نفس العملية) .

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

إذا تم إرسال إشارة إلى عملية نائمة، فيجب إيقاظها قبل أن تعود إلى مساحة المستخدم وبالتالي معالجة الإشارة المعلقة.هنا لدينا الفرق بين نوعين رئيسيين من النوم:

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

TASK_KILLABLE (المذكور في مقالة LWN المرتبطة بإجابة ddaa) هو متغير جديد.

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

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

عادةً ما تنتظر العمليات غير المنقطعة الإدخال/الإخراج بعد حدوث خطأ في الصفحة.

النظر في هذا:

  • يحاول مؤشر الترابط الوصول إلى صفحة ليست في المركز (إما ملف قابل للتنفيذ تم تحميله حسب الطلب، أو صفحة من الذاكرة المجهولة التي تم تبديلها، أو ملف mmap()'d الذي تم تحميله عند الطلب، وهو إلى حد كبير نفس الشيء)
  • النواة الآن (تحاول) تحميلها
  • لا يمكن أن تستمر العملية حتى تصبح الصفحة متاحة.

لا يمكن مقاطعة العملية/المهمة في هذه الحالة، لأنها لا تستطيع التعامل مع أي إشارات؛إذا حدث ذلك، سيحدث خطأ آخر في الصفحة وستعود إلى حيث كانت.

عندما أقول "عملية"، أعني حقًا "مهمة"، والتي تُترجم تقريبًا في نظام التشغيل Linux (2.6) إلى "سلسلة محادثات" والتي قد تحتوي أو لا تحتوي على إدخال "مجموعة مؤشرات ترابط" فردي في /proc

وفي بعض الحالات، قد يكون الانتظار لفترة طويلة.من الأمثلة النموذجية على ذلك مكان وجود الملف القابل للتنفيذ أو ملف mmap'd على نظام ملفات الشبكة حيث فشل الخادم.إذا نجح الإدخال/الإخراج في النهاية، فستستمر المهمة.إذا فشلت في النهاية، فستحصل المهمة بشكل عام على SIGBUS أو شيء من هذا القبيل.

بالنسبة لسؤالك الثالث:أعتقد أنه يمكنك إيقاف العمليات غير المنقطعة عن طريق التشغيلsudo kill -HUP 1.سيتم إعادة تشغيل الحرف init دون إنهاء العمليات الجارية وبعد تشغيله، ستختفي العمليات غير المنقطعة.

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

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

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