إعادة الدخول (الحوسبة)
في البرمجة، تُعرف خاصية إعادة الدخول بأنها قدرة الدالة أو الروتين الفرعي على التوقف ثم استئناف التنفيذ قبل اكتماله. وهذا يعني إمكانية استدعاء الدالة مرة أخرى قبل إتمام تنفيذها السابق. يُصمم الكود القابل لإعادة الدخول ليكون آمنًا وقابلًا للتنبؤ عند استدعاء عدة نسخ من الدالة نفسها في وقت واحد أو بتتابع سريع. يُطلق على برنامج الحاسوب أو الروتين الفرعي اسم "قابل لإعادة الدخول" إذا كان بالإمكان تشغيل عدة استدعاءات منه بشكل متزامن وآمن على معالجات متعددة ، أو إذا كان بالإمكان مقاطعة تنفيذه على نظام أحادي المعالج وبدء تنفيذ جديد له بأمان (أي إعادة الدخول إليه). قد تحدث المقاطعة نتيجة إجراء داخلي مثل القفز أو الاستدعاء (والذي قد يكون استدعاءً تكراريًا ؛ فإعادة الدخول إلى الدالة هي تعميم للاستدعاء التكراري)، أو نتيجة إجراء خارجي مثل المقاطعة أو الإشارة .
ينبع هذا التعريف من بيئات البرمجة المتعددة ، حيث قد تنشط عدة عمليات في وقت واحد، وحيث يمكن مقاطعة تدفق التحكم ونقله إلى روتين خدمة المقاطعة (ISR) أو روتين "المعالج". يجب أن يكون أي روتين فرعي يستخدمه المعالج، والذي كان من المحتمل أن يكون قيد التنفيذ عند حدوث المقاطعة، قابلاً لإعادة الدخول. وبالمثل، يجب أن يكون الكود المشترك بين معالجين يصلان إلى بيانات مشتركة قابلاً لإعادة الدخول. غالبًا ما تكون الروتينات الفرعية التي يمكن الوصول إليها عبر نواة نظام التشغيل غير قابلة لإعادة الدخول. لذا، فإن روتينات خدمة المقاطعة محدودة في الإجراءات التي يمكنها تنفيذها؛ على سبيل المثال، عادةً ما تكون ممنوعة من الوصول إلى نظام الملفات ، وأحيانًا حتى من تخصيص الذاكرة .
لا يُعدّ إمكانية إعادة الدخول شرطًا ضروريًا ولا كافيًا لضمان سلامة البرنامج في بيئات متعددة الخيوط. بعبارة أخرى، يمكن أن يكون الروتين الفرعي القابل لإعادة الدخول آمنًا في بيئات متعددة الخيوط، [ 1 ] ولكنه ليس مضمونًا. [ 2 ] في المقابل، لا يشترط أن يكون الكود الآمن في بيئات متعددة الخيوط قابلًا لإعادة الدخول (انظر الأمثلة أدناه).
من المصطلحات الأخرى المستخدمة للبرامج القابلة لإعادة الدخول مصطلح "البرنامج القابل للمشاركة". [ 3 ] تُصنّف الإجراءات الفرعية القابلة لإعادة الدخول أحيانًا في المراجع على أنها "آمنة للإشارات". [ 4 ] غالبًا ما تكون البرامج القابلة لإعادة الدخول " إجراءات بحتة" .
خلفية
لا يُعدّ مفهوم إعادة الدخول مرادفًا لمفهوم التكرار ، حيث يمكن استدعاء الدالة أكثر من مرة ومع ذلك تُنتج نفس المخرجات تمامًا كما لو تم استدعاؤها مرة واحدة فقط. بشكل عام، تُنتج الدالة بيانات مخرجات بناءً على بيانات مُدخلات (مع أن كليهما اختياري في الغالب). يمكن لأي دالة الوصول إلى البيانات المشتركة في أي وقت. إذا كان بإمكان أي دالة تغيير البيانات (ولا تحتفظ أي منها بسجل لهذه التغييرات)، فلا يوجد ما يضمن للدوال التي تشترك في البيانات أن هذه البيانات هي نفسها كما كانت في أي وقت سابق.
تتمتع البيانات بخاصية تسمى النطاق ، والتي تحدد مكان استخدام البيانات في البرنامج. يكون نطاق البيانات إما عامًا (خارج نطاق أي دالة وبامتداد غير محدد) أو محليًا (يتم إنشاؤه في كل مرة يتم فيها استدعاء دالة ويتم حذفه عند الخروج).
لا تتم مشاركة البيانات المحلية بين أي إجراءات، سواء أُعيد إدخالها أم لا؛ لذا، فهي لا تؤثر على إعادة الإدخال. تُعرَّف البيانات العامة خارج الدوال، ويمكن الوصول إليها من قِبل أكثر من دالة، إما على شكل متغيرات عامة (بيانات مشتركة بين جميع الدوال)، أو كمتغيرات ثابتة (بيانات مشتركة بين جميع استدعاءات الدالة نفسها). في البرمجة كائنية التوجه ، تُعرَّف البيانات العامة ضمن نطاق فئة، ويمكن أن تكون خاصة، مما يجعلها متاحة فقط لدوال تلك الفئة. يوجد أيضًا مفهوم متغيرات النسخة ، حيث يرتبط متغير الفئة بنسخة من تلك الفئة. لهذه الأسباب، في البرمجة كائنية التوجه، يُستخدم هذا التمييز عادةً للبيانات التي يمكن الوصول إليها خارج الفئة (عامة)، وللبيانات المستقلة عن نسخ الفئة (ثابتة).
يختلف مفهوم إعادة الدخول عن مفهوم أمان الخيوط ، ولكنه يرتبط به ارتباطًا وثيقًا . فقد تكون الدالة آمنة للخيوط ومع ذلك غير قابلة لإعادة الدخول. على سبيل المثال، يمكن تغليف دالة ما بالكامل باستخدام قفل تبادلي (مما يتجنب المشاكل في بيئات تعدد الخيوط)، ولكن إذا استُخدمت هذه الدالة في روتين خدمة مقاطعة، فقد تتوقف عن العمل في انتظار التنفيذ الأول لتحرير القفل التبادلي. يكمن جوهر تجنب الالتباس في أن إعادة الدخول تشير إلى تنفيذ خيط واحد فقط . وهو مفهوم يعود إلى زمن لم تكن فيه أنظمة التشغيل متعددة المهام موجودة.
قواعد إعادة الدخول
- لا يجوز أن يحتوي الكود القابل لإعادة الدخول على أي بيانات ثابتة أو عامة غير ثابتة بدون مزامنة .
- يمكن للدوال القابلة لإعادة الدخول التعامل مع البيانات العامة. على سبيل المثال، يمكن لروتين خدمة المقاطعة القابل لإعادة الدخول الحصول على جزء من حالة الجهاز للعمل معه (مثل مخزن قراءة المنفذ التسلسلي)، وهو ليس فقط عامًا، بل متقلبًا أيضًا. مع ذلك، لا يُنصح بالاستخدام المعتاد للمتغيرات الثابتة والبيانات العامة، بمعنى أنه باستثناء أجزاء التعليمات البرمجية المتزامنة ، يجب استخدام تعليمات القراءة والتعديل والكتابة الذرية فقط في هذه المتغيرات (يجب ألا يكون من الممكن حدوث مقاطعة أو إشارة أثناء تنفيذ مثل هذه التعليمات). تجدر الإشارة إلى أنه في لغة C، حتى عملية القراءة أو الكتابة ليست مضمونة أن تكون ذرية؛ فقد تُقسّم إلى عدة عمليات قراءة أو كتابة. [ 5 ] يوفر معيار C وSUSv3 هذا الغرض، على الرغم من أنه يضمن فقط عمليات القراءة والكتابة البسيطة، وليس عمليات الزيادة أو النقصان. [ 6 ] تتوفر عمليات ذرية أكثر تعقيدًا في C11 ، والتي توفر ...
sig_atomic_tstdatomic.h - لا يجوز للبرنامج القابل لإعادة الدخول تعديل نفسه دون مزامنة.
- قد يسمح نظام التشغيل لعملية ما بتعديل شفرتها البرمجية. وهناك أسباب عديدة لذلك (مثل معالجة الرسومات بسرعة)، ولكن هذا يتطلب عمومًا مزامنة لتجنب مشاكل إعادة الدخول.
مع ذلك، قد يُعدّل البرنامج نفسه إذا كان موجودًا في ذاكرته الخاصة. أي، إذا استخدم كل استدعاء جديد موقعًا مختلفًا في رمز الآلة حيث تُنسخ الشفرة الأصلية، فلن يؤثر ذلك على الاستدعاءات الأخرى حتى لو عدّل البرنامج نفسه أثناء تنفيذ ذلك الاستدعاء (الخيط) المحدد.
- لا يجوز للتعليمات البرمجية القابلة لإعادة الدخول استدعاء برامج أو إجراءات حاسوبية غير قابلة لإعادة الدخول دون تزامن.
- تُعقّد مستويات الأولوية المتعددة للمستخدم أو الكائن أو العملية، أو المعالجة المتعددة، عادةً التحكم في التعليمات البرمجية القابلة لإعادة الدخول. من المهم تتبع أي وصول أو آثار جانبية تتم داخل روتين مصمم ليكون قابلاً لإعادة الدخول.
تعتمد إمكانية إعادة دخول روتين فرعي يعمل على موارد نظام التشغيل أو بيانات غير محلية على ذرية العمليات المعنية. على سبيل المثال، إذا قام الروتين الفرعي بتعديل متغير عام 64 بت على جهاز 32 بت، فقد تُقسّم العملية إلى عمليتين 32 بت، وبالتالي، إذا تمت مقاطعة الروتين الفرعي أثناء التنفيذ، ثم استدعاؤه مرة أخرى من معالج المقاطعة، فقد يكون المتغير العام في حالة تم فيها تحديث 32 بت فقط. قد توفر لغة البرمجة ضمانات ذرية للمقاطعة الناتجة عن إجراء داخلي مثل القفز أو الاستدعاء. عندئذٍ، سترى الدالة fفي تعبير مثل (global:=1) + (f())، حيث قد يكون ترتيب تقييم التعبيرات الفرعية عشوائيًا في لغة البرمجة، المتغير العام إما مُعيّنًا إلى 1 أو إلى قيمته السابقة، ولكن ليس في حالة وسيطة تم فيها تحديث جزء فقط. (يمكن أن يحدث هذا الأخير في لغة C ، لأن التعبير لا يحتوي على نقطة تسلسل .) قد يوفر نظام التشغيل ضمانات ذرية للإشارات ، مثل استدعاء نظام مُقاطع بإشارة لا يكون له تأثير جزئي. وقد يوفر معالج الأجهزة ضمانات ذرية للمقاطعات ، مثل تعليمات المعالج المُقاطعة التي لا يكون لها تأثيرات جزئية.
أمثلة
ولتوضيح إعادة الدخول، تستخدم هذه المقالة كمثال دالة مساعدة بلغة Cswap() ، تأخذ مؤشرين وتقوم بتبديل قيمهما، وروتين معالجة المقاطعات الذي يستدعي أيضًا دالة التبديل.
لا يمكن إعادة الدخول إليها ولا يمكن استخدامها مع الخيوط
هذا مثال على دالة تبديل غير قابلة لإعادة الدخول أو آمنة للاستخدام في بيئات متعددة الخيوط. بما أن tmpالمتغير مُشترك عالميًا، دون تزامن، بين أي نسخ متزامنة من الدالة، فقد تتداخل إحدى النسخ مع البيانات التي تعتمد عليها نسخة أخرى. لذلك، كان من الأفضل عدم استخدامها في روتين خدمة المقاطعة isr().
int tmp ;void swap ( int * x , int * y ) { tmp = * x ; * x = * y ; /* قد يستدعي مقاطعة الأجهزة isr() هنا. */ * y = tmp ; }void isr () { int x = 1 , y = 2 ; swap ( & x , & y ); }آمن للاستخدام المتزامن ولكنه غير قابل لإعادة الدخول
swap()يمكن جعل الدالة في المثال السابق آمنة للاستخدام في بيئة متعددة الخيوط عن طريق جعلها tmpمحلية للخيط . ومع ذلك، فإنها لا تزال غير قابلة لإعادة الدخول، وسيستمر هذا في التسبب بمشاكل إذا isr()تم استدعاؤها في نفس سياق خيط قيد التنفيذ بالفعل swap().
_Thread_local int tmp ;void swap ( int * x , int * y ) { tmp = * x ; * x = * y ; /* قد يستدعي مقاطعة الأجهزة isr() هنا. */ * y = tmp ; }void isr () { int x = 1 , y = 2 ; swap ( & x , & y ); }قابل لإعادة الدخول وآمن للخيوط
إنّ تطبيقًا swap()يُخصّص الذاكرة tmpعلى المكدس بدلًا من تخصيصها عالميًا، ويُستدعى فقط باستخدام متغيرات غير مشتركة كمعاملات [ ب ] ، يُعدّ آمنًا للاستخدام المتزامن وقابلًا لإعادة الدخول. آمن للاستخدام المتزامن لأنّ المكدس خاص بكل خيط، ودالة تعمل على البيانات المحلية فقط ستُنتج دائمًا النتيجة المتوقعة. لا يوجد وصول إلى البيانات المشتركة، وبالتالي لا يوجد تضارب في البيانات.
void swap ( int * x , int * y ) { int tmp ; tmp = * x ; * x = * y ; * y = tmp ; /* قد يستدعي مقاطعة الأجهزة isr() هنا. */ }void isr () { int x = 1 , y = 2 ; swap ( & x , & y ); }معالج المقاطعة القابلة لإعادة الدخول
معالج المقاطعة القابل لإعادة الدخول هو معالج مقاطعة يُعيد تفعيل المقاطعات في وقت مبكر من تنفيذه. قد يُقلل هذا من زمن استجابة المقاطعة . [ 7 ] عمومًا، عند برمجة إجراءات خدمة المقاطعة، يُنصح بإعادة تفعيل المقاطعات في أسرع وقت ممكن في معالج المقاطعة. تُساعد هذه الممارسة على تجنب فقدان المقاطعات. [ 8 ]
أمثلة أخرى
في الكود التالي، لا يمكن إعادة استخدام fأي من الدالتين.g
int v = 1 ;int f () { v += 2 ; return v ; }int g () { return f () + 2 ; }في المثال أعلاه، f()يعتمد على متغير عام غير ثابت v؛ لذا، إذا f()تمت مقاطعة التنفيذ بواسطة روتين خدمة مقاطعة (ISR) يُعدّل قيمة v، فإن إعادة الدخول إلى f()سيعيد قيمة خاطئة لـ v. لا يمكن التنبؤ بقيمة v، وبالتالي قيمة الإرجاع لـ f، بدقة: ستختلفان اعتمادًا على ما إذا كانت المقاطعة قد عدّلت قيمة vأثناء fتنفيذ . لذلك، fفإن غير قابلة لإعادة الدخول. وكذلك g، لأنها تستدعي f، وهي غير قابلة لإعادة الدخول.
هذه النسخ المعدلة قليلاً قابلة لإعادة الدخول:
int f ( int i ) { return i + 2 ; }int g ( int i ) { return f ( i ) + 2 ; }فيما يلي، الدالة آمنة للاستخدام في بيئة متعددة الخيوط، ولكنها ليست (بالضرورة) قابلة لإعادة الدخول:
دالة int ( ) { mutex_lock ();// ... // جسم الدالة // ...mutex_unlock (); }في المثال أعلاه، function()يمكن استدعاء الدالة من قبل خيوط تنفيذ مختلفة دون أي مشكلة. ولكن، إذا استُخدمت الدالة في معالج مقاطعة قابل لإعادة الدخول، وحدثت مقاطعة ثانية داخل الدالة، فسيتوقف الروتين الثاني إلى الأبد. ولأن معالجة المقاطعات قد تُعطّل مقاطعات أخرى، فقد يتأثر النظام بأكمله.
ملحوظات
انظر أيضاً
مراجع
- ↑ كيريسك 2010 ، ص 657 .
- ↑ "كتابة كود قابل لإعادة الدخول وآمن للاستخدام المتزامن" . البرمجة لنظام AIX . شركة IBM . تم الاطلاع عليه بتاريخ 12-05-2025 .
- ↑ رالستون 2000 ، ص 1514-1515.
- ↑ "pthread_cond_init()--تهيئة متغير الشرط" . مركز معارف IBM . تم الاطلاع عليه بتاريخ 5 أكتوبر 2019 .
- ↑ بريشينغ، جيف (18-06-2013). "العمليات الذرية مقابل العمليات غير الذرية" . بريشينغ في البرمجة . تم الاسترجاع في 24-04-2018 .
{{cite web}}: CS1 maint: deprecated archiveal service ( link ) - ↑ كيريسك 2010 ، ص 428 .
- ^ سلوس وآخرون. 2004 ، ص. 342 .
- ↑ ريغير، جون (2006). "الاستخدام الآمن والمنظم للمقاطعات في البرمجيات المضمنة والأنظمة في الوقت الحقيقي" (ملف PDF) . دليل الأنظمة المضمنة والأنظمة في الوقت الحقيقي . مطبعة CRC . مؤرشف (ملف PDF) من النسخة الأصلية بتاريخ 24 أغسطس 2007 - عبر موقع المؤلف الإلكتروني في كلية علوم الحاسوب بجامعة يوتا.
المراجع
- كيريسك، مايكل (2010). واجهة برمجة لينكس . دار نشر نو ستارش .
- رالستون، أنتوني، محرر. (2000). "برنامج إعادة الدخول". موسوعة علوم الحاسوب ( الطبعة الرابعة). مجموعة نيتشر للنشر .
- سلوس، أندرو ن.؛ سايمز، دومينيك؛ رايت، كريس ؛ رايفيلد، جون (2004). دليل مطوري أنظمة ARM . دار نشر مورغان كوفمان. ISBN 9780080490496.
للمزيد من القراءة
- تشين، ريموند (29 يونيو 2004). "الفرق بين أمان الخيوط وإعادة الدخول" . الشيء القديم الجديد . شبكة مطوري مايكروسوفت . تم الاسترجاع في 24 أبريل 2018 .
{{cite web}}: CS1 maint: deprecated archiveal service ( link ) - غانسل، جاك (15 مارس 2001). "مقدمة في إعادة الدخول" . Embedded.com . تم الاطلاع عليه بتاريخ 24 أبريل 2018 .
{{cite web}}: CS1 maint: deprecated archiveal service ( link ) - آي بي إم (2018). "مفاهيم البرمجة العامة" (ملف PDF) . دليل نظام التشغيل AIX الإصدار 7.2 . الصفحات 636-641 . تاريخ الاسترجاع: 24 أبريل 2018 .
- جها، ديباك (20 يناير 2005). "استخدام الدوال القابلة لإعادة الدخول لمعالجة الإشارات بشكل أكثر أمانًا" . IBM DeveloperWorks . تم الاطلاع عليه بتاريخ 24 أبريل 2018 .
{{cite web}}: CS1 maint: deprecated archiveal service ( link )
- التزامن (علوم الحاسوب)
- التكرار
- البرامج الفرعية
