ترتيب الذاكرة
ترتيب الذاكرة هو ترتيب وصول وحدة المعالجة المركزية (CPU ) إلى ذاكرة الحاسوب . يعتمد ترتيب الذاكرة على كلٍ من ترتيب التعليمات التي يُنشئها المُصرّف أثناء عملية الترجمة، وترتيب تنفيذ وحدة المعالجة المركزية أثناء وقت التشغيل . [ 1 ] [ 2 ] مع ذلك، لا يُعدّ ترتيب الذاكرة ذا أهمية كبيرة خارج نطاق تعدد الخيوط والإدخال /الإخراج المُرتبط بالذاكرة ، لأنه إذا غيّر المُصرّف أو وحدة المعالجة المركزية ترتيب أي عملية ، فعليه بالضرورة ضمان عدم تغيير مُخرجات التعليمات البرمجية العادية أحادية الخيط نتيجةً لإعادة الترتيب . [ 1 ] [ 2 ] [ 3 ]
يُقال إن ترتيب الذاكرة قوي أو متسق تسلسليًا عندما يكون ترتيب العمليات غير قابل للتغيير، أو عندما لا يكون لهذه التغييرات أي تأثير ملحوظ على أي خيط. [ 1 ] [ 4 ] في المقابل، يُسمى ترتيب الذاكرة ضعيفًا أو متساهلًا عندما لا يستطيع خيط واحد التنبؤ بترتيب العمليات الناشئة عن خيط آخر. [ 1 ] [ 4 ] تفشل العديد من الخوارزميات المتوازية المكتوبة ببساطة عند تجميعها أو تنفيذها بترتيب ذاكرة ضعيف. [ 5 ] [ 6 ] غالبًا ما تُحل هذه المشكلة بإضافة تعليمات حاجز الذاكرة إلى البرنامج. [ 6 ] [ 7 ]
للاستفادة الكاملة من عرض النطاق الترددي لأنواع الذاكرة المختلفة، مثل ذاكرة التخزين المؤقت ووحدات الذاكرة ، لا تضمن سوى قلة من المترجمات أو بنى المعالجات المركزية ترتيبًا قويًا تمامًا. [ 1 ] [ 5 ] ومن بين البنى الشائعة الاستخدام، تتمتع معالجات x86-64 بأقوى ترتيب للذاكرة، ولكنها قد تؤجل تعليمات تخزين البيانات في الذاكرة إلى ما بعد تعليمات تحميلها. [ 5 ] [ 8 ] وعلى النقيض من ذلك، لا تقدم معالجات DEC Alpha أي ضمانات تُذكر بشأن ترتيب الذاكرة. [ 5 ]
ترتيب الذاكرة في وقت الترجمة
تتضمن معظم لغات البرمجة مفهومًا ما لسلسلة التنفيذ التي تُنفذ التعليمات بترتيب محدد. تقوم المترجمات التقليدية بترجمة التعبيرات عالية المستوى إلى سلسلة من التعليمات منخفضة المستوى نسبةً إلى عداد البرنامج على مستوى الآلة الأساسية.
تظهر آثار التنفيذ على مستويين: داخل كود البرنامج على مستوى عالٍ، وعلى مستوى الجهاز كما تراه الخيوط الأخرى أو عناصر المعالجة في البرمجة المتزامنة ، أو أثناء تصحيح الأخطاء عند استخدام أداة تصحيح أخطاء للأجهزة تتيح الوصول إلى حالة الجهاز (غالبًا ما يكون بعض الدعم لهذا مُدمجًا مباشرةً في وحدة المعالجة المركزية أو المتحكم الدقيق كدائرة مستقلة وظيفيًا عن نواة التنفيذ التي تستمر في العمل حتى عند إيقاف النواة نفسها لإجراء فحص ثابت لحالة تنفيذها). يهتم ترتيب الذاكرة في وقت الترجمة بالمستوى الأول، ولا يهتم بالمستويات الأخرى.
مسائل عامة تتعلق بترتيب البرنامج
تأثيرات ترتيب البرنامج على تقييم التعبير
أثناء عملية الترجمة، غالبًا ما تُولَّد تعليمات الأجهزة بمستوى تفصيل أدق مما هو مُحدد في الكود عالي المستوى. التأثير الملحوظ الرئيسي في لغة البرمجة الإجرائية هو إسناد قيمة جديدة إلى متغير مُسمى.
المجموع = أ + ب + ج؛ print(sum);
تأتي عبارة الطباعة بعد العبارة التي تُسند قيمةً إلى المتغير sum، وبالتالي عندما تُشير عبارة الطباعة إلى المتغير المحسوب، sumفإنها تُشير إلى هذه النتيجة كأثرٍ واضحٍ لتسلسل التنفيذ السابق. وكما هو مُحددٌ في قواعد تسلسل البرنامج، عندما printتُشير استدعاءات الدوال إلى قيمة المتغير sum sum، يجب أن تكون قيمة sum sumهي قيمة آخر عملية إسنادٍ نُفذت إلى المتغير sum sum(في هذه الحالة، العبارة السابقة مباشرةً).
على مستوى الآلة، لا تستطيع سوى قلة من الآلات جمع ثلاثة أعداد في تعليمة واحدة، لذا سيتعين على المترجم ترجمة هذا التعبير إلى عمليتي جمع. إذا كانت دلالات لغة البرمجة تُقيد المترجم بترجمة التعبير من اليسار إلى اليمين (على سبيل المثال)، فسيبدو الكود المُولّد كما لو أن المبرمج قد كتب العبارات التالية في البرنامج الأصلي:
المجموع = أ + ب؛ المجموع = المجموع + ج؛
إذا سُمح للمترجم باستغلال خاصية التجميع في عملية الجمع، فقد يقوم بدلاً من ذلك بتوليد ما يلي:
المجموع = ب + ج؛ المجموع = أ + المجموع؛
إذا سُمح للمترجم أيضًا باستغلال خاصية التبادل في الجمع، فقد يقوم بدلاً من ذلك بتوليد ما يلي:
المجموع = أ + ج؛ المجموع = المجموع + ب؛
لاحظ أن نوع البيانات الصحيحة في معظم لغات البرمجة يتبع فقط الجبر للأعداد الصحيحة الرياضية في حالة عدم وجود تجاوز في عدد صحيح، وأن العمليات الحسابية ذات الفاصلة العائمة على نوع البيانات ذات الفاصلة العائمة المتاح في معظم لغات البرمجة ليست تجميعية بسبب التقريب الوسيط، مما يجعل تأثيرات ترتيب التعبير مرئية في اختلافات صغيرة في النتيجة المحسوبة (ومع ذلك، قد تتسلسل الاختلافات الأولية الصغيرة إلى اختلافات كبيرة بشكل تعسفي على مدار عملية حسابية أطول).
إذا كان المبرمج قلقًا بشأن تجاوز سعة الأعداد الصحيحة أو تأثيرات التقريب في الأعداد العشرية، فيمكن كتابة نفس البرنامج على المستوى العالي الأصلي على النحو التالي:
المجموع = أ + ب؛ المجموع = المجموع + ج؛
تأثيرات ترتيب البرنامج التي تتضمن استدعاءات الدوال
تتعامل العديد من لغات البرمجة مع حدود العبارات كنقطة تسلسل ، مما يُجبر على إتمام جميع آثار عبارة ما قبل تنفيذ العبارة التالية. وهذا بدوره يُجبر المُترجم على توليد شيفرة تتوافق مع ترتيب العبارات المُعبر عنها. مع ذلك، غالبًا ما تكون العبارات أكثر تعقيدًا، وقد تحتوي على استدعاءات دوال داخلية .
المجموع = f(a) + g(b) + h(c)؛
على مستوى الآلة، يتطلب استدعاء دالة عادةً إنشاء إطار مكدس لاستدعاء الدالة، وهو ما يستلزم عمليات قراءة وكتابة متعددة في ذاكرة الآلة. في معظم لغات البرمجة المترجمة، يكون للمترجم حرية ترتيب استدعاءات الدوال fكما gيراه hمناسبًا، مما يؤدي إلى تغييرات واسعة النطاق في ترتيب ذاكرة البرنامج. في لغة برمجة وظيفية بحتة ، يُمنع أن يكون لاستدعاءات الدوال أي تأثيرات جانبية على حالة البرنامج المرئية (باستثناء قيمة الإرجاع )، وبالتالي فإن اختلاف ترتيب ذاكرة الآلة الناتج عن ترتيب استدعاء الدوال لن يؤثر على دلالات البرنامج. أما في لغات البرمجة الإجرائية، فقد يكون للدوال المستدعاة تأثيرات جانبية، مثل إجراء عملية إدخال/إخراج ، أو تحديث متغير في نطاق البرنامج العام، وكلاهما يُنتج تأثيرات مرئية على نموذج البرنامج.
ومرة أخرى، يمكن للمبرمج المهتم بهذه التأثيرات أن يصبح أكثر دقة في التعبير عن برنامج المصدر الأصلي:
المجموع = f(a)؛ المجموع = المجموع + g(b)؛ المجموع = المجموع + h(c)؛
في لغات البرمجة حيث يتم تعريف حدود العبارة كنقطة تسلسل، يجب الآن تنفيذ استدعاءات الدالة f، g، و hبهذا الترتيب الدقيق.
قضايا محددة تتعلق بترتيب الذاكرة
تأثيرات ترتيب البرنامج التي تتضمن تعبيرات المؤشر
والآن، لننظر إلى نفس عملية الجمع معبرًا عنها باستخدام التوجيه غير المباشر للمؤشرات، في لغة مثل C أو C++ التي تدعم المؤشرات :
المجموع = *أ + *ب + *ج؛
يُطلق على تقييم التعبير *xاسم " فك مرجعية " المؤشر، ويتضمن قراءة البيانات من الذاكرة في موقع محدد بالقيمة الحالية للمؤشر x. وتُحدد آثار القراءة من المؤشر بنموذج الذاكرة الخاص بالمعمارية . عند القراءة من وحدة تخزين البرنامج القياسية، لا توجد آثار جانبية ناتجة عن ترتيب عمليات قراءة الذاكرة. في برمجة الأنظمة المدمجة ، من الشائع جدًا استخدام الإدخال/الإخراج المُمَثَّل في الذاكرة، حيث تُؤدي عمليات القراءة والكتابة إلى الذاكرة إلى تشغيل عمليات الإدخال/الإخراج، أو تغييرات في وضع تشغيل المعالج، وهي آثار جانبية واضحة. في المثال أعلاه، افترض مؤقتًا أن المؤشرات تُشير إلى ذاكرة البرنامج العادية، دون هذه الآثار الجانبية. للمُصرِّف حرية إعادة ترتيب عمليات القراءة هذه وفقًا لترتيب البرنامج كما يراه مناسبًا، ولن تكون هناك أي آثار جانبية مرئية للبرنامج.
ماذا لو كانت القيمة المُسندة أيضاً غير مباشرة عبر المؤشر؟
*المجموع = *أ + *ب + *ج؛
من غير المرجح أن يسمح تعريف اللغة هنا للمترجم بتقسيم هذا على النحو التالي:
// كما أعاد المترجم كتابتها // ممنوع عموماً *المجموع = *أ + *ب؛ *sum = *sum + *c;
لن يُعتبر هذا الأسلوب فعالاً في معظم الحالات، وقد تُؤثر عمليات الكتابة على المؤشرات سلبًا على حالة الجهاز الظاهرة. ولأن المُصرّف غير مُصرّح له بهذا التحويل التقسيمي تحديدًا، فإن الكتابة الوحيدة إلى موقع الذاكرة sumيجب أن تتبع منطقيًا عمليات قراءة المؤشرات الثلاث في تعبير القيمة.
لنفترض، مع ذلك، أن المبرمج مهتم بالدلالات المرئية لتجاوز سعة العدد الصحيح، ويقوم بتقسيم العبارة على مستوى البرنامج كما يلي:
// كما كتبها المبرمج مباشرةً // مع مراعاة مخاوف التداخل *المجموع = *أ + *ب؛ *sum = *sum + *c;
تُشفّر العبارة الأولى عمليتي قراءة من الذاكرة، يجب أن تسبقا (بأي ترتيب) عملية الكتابة الأولى *sum. أما العبارة الثانية فتشفّر عمليتي قراءة من الذاكرة (بأي ترتيب) يجب أن تسبقا التحديث الثاني *sum. يضمن هذا ترتيب عمليتي الجمع، ولكنه قد يُسبب مشكلة جديدة تتعلق بتداخل العناوين : إذ يُمكن لأي من هذه المؤشرات أن يُشير إلى نفس موقع الذاكرة.
على سبيل المثال، لنفترض في هذا المثال أن *cو *sumيتم ربطهما بنفس موقع الذاكرة، وإعادة كتابة كلا الإصدارين من البرنامج مع *sumاستبدال كليهما.
*sum = *a + *b + *sum;
لا توجد مشاكل هنا. القيمة الأصلية لما كتبناه في الأصل *cتُفقد عند إسنادها إلى *sum، وكذلك القيمة الأصلية لـ ، *sumولكن هذه القيمة تم استبدالها في المقام الأول، ولا داعي للقلق بشأنها.
// ما يصبح عليه البرنامج عند استخدام *c و *sum مع الأسماء المستعارة *المجموع = *أ + *ب؛ *sum = *sum + *sum;
هنا يتم استبدال القيمة الأصلية *sumقبل الوصول إليها لأول مرة، وبدلاً من ذلك نحصل على المكافئ الجبري لـ:
// المكافئ الجبري للحالة المستعارة أعلاه *sum = (*a + *b) + (*a + *b);
مما يُعطي قيمة مختلفة تمامًا *sumبسبب إعادة ترتيب العبارة.
بسبب احتمالية حدوث تداخل في أسماء المؤشرات، يصعب إعادة ترتيبها دون المخاطرة بظهور آثار واضحة على البرنامج. في الحالة الشائعة، قد لا يكون هناك أي تداخل، وبالتالي يبدو أن الكود يعمل بشكل طبيعي كما كان من قبل. ولكن في الحالات النادرة التي يكون فيها التداخل موجودًا، قد ينتج عن ذلك أخطاء برمجية جسيمة. حتى لو كانت هذه الحالات النادرة غائبة تمامًا في التنفيذ العادي، فإنها تفتح المجال أمام مهاجم خبيث لابتكار مدخلات تحتوي على تداخل، مما قد يؤدي إلى استغلال ثغرة أمنية في النظام .
إعادة ترتيب البرنامج السابق بشكل آمن هي كما يلي:
// تعريف متغير محلي مؤقت 'temp' من نوع مناسب temp = *a + *b; *sum = temp + *c;
وأخيراً، لننظر في الحالة غير المباشرة مع إضافة استدعاءات الدوال:
*sum = f(*a) + g(*b);
قد يختار المترجم تقييم الدالة *a`f` *bقبل استدعاء أي من الدالتين، أو قد يؤجل تقييم الدالة `f` *bإلى ما بعد استدعاء الدالة `f` f، أو قد يؤجل تقييم الدالة `f` *aإلى ما بعد استدعاء الدالة `f` g. إذا كانت الدالتان `f` fو`f` gخاليتين من أي آثار جانبية مرئية للبرنامج، فإن الخيارات الثلاثة ستنتج برنامجًا بنفس الآثار المرئية. أما إذا كان تنفيذ الدالة ` ff` أو g`f` يتضمن أثرًا جانبيًا لأي عملية كتابة مؤشر تخضع للتداخل مع المؤشرات `f` aأو `f` b، فإن الخيارات الثلاثة قد تنتج آثارًا مرئية مختلفة للبرنامج.
ترتيب الذاكرة في مواصفات اللغة
بشكل عام، لا تُفصّل لغات البرمجة المُصرّفة مواصفاتها بما يكفي ليتمكن المُصرّف من تحديد المؤشرات التي قد تكون مُعرّضة للتداخل (aliasing) وتلك التي لا تكون كذلك، وذلك أثناء عملية التصريف. لذا، يُعدّ افتراض المُصرّف أن جميع المؤشرات مُعرّضة للتداخل في جميع الأوقات هو الخيار الأكثر أمانًا. إلا أن هذا المستوى من التشاؤم المُتحفّظ يُؤدي عادةً إلى أداء ضعيف للغاية مُقارنةً بالافتراض المُتفائل بعدم وجود أي تداخل على الإطلاق.
ونتيجة لذلك، تطورت العديد من لغات البرمجة عالية المستوى، مثل C/C++، لتتضمن مواصفات دلالية معقدة ومتطورة حول المواضع التي يُسمح فيها للمترجم بوضع افتراضات متفائلة في إعادة ترتيب التعليمات البرمجية سعياً وراء أعلى أداء ممكن، والمواضع التي يُطلب فيها من المترجم وضع افتراضات متشائمة في إعادة ترتيب التعليمات البرمجية لتجنب المخاطر الدلالية.
تُعدّ عمليات الكتابة في الذاكرة الفئة الأكبر من الآثار الجانبية في لغات البرمجة الإجرائية الحديثة، لذا تُشكّل قواعد ترتيب الذاكرة عنصرًا أساسيًا في تعريف دلالات ترتيب البرنامج. قد يبدو إعادة ترتيب استدعاءات الدوال المذكورة أعلاه أمرًا مختلفًا، لكنه عادةً ما يتطور إلى مخاوف بشأن تأثيرات الذاكرة الداخلية للدوال المستدعاة التي تتفاعل مع عمليات الذاكرة في التعبير الذي يُولّد استدعاء الدالة.
صعوبات ومضاعفات إضافية
التحسين في ظل الوضع الافتراضي
تتجاوز المترجمات الحديثة هذا الحد أحيانًا باستخدام قاعدة "كما لو" ، حيث يُسمح بأي إعادة ترتيب (حتى بين العبارات) إذا لم يؤثر ذلك على دلالات البرنامج الظاهرة. وبموجب هذه القاعدة، قد يختلف ترتيب العمليات في الكود المترجم اختلافًا كبيرًا عن ترتيب البرنامج المحدد. إذا سُمح للمترجم بوضع افتراضات متفائلة حول عدم وجود تداخل بين تعابير المؤشرات المختلفة في حالة وجود هذا التداخل فعليًا (وهو ما يُصنف عادةً على أنه برنامج غير سليم يُظهر سلوكًا غير مُحدد )، فإن النتائج السلبية لتحويل تحسين الكود بشكل مفرط يستحيل التنبؤ بها قبل تنفيذ الكود أو فحصه مباشرةً. إن مجال السلوك غير المُحدد له مظاهر لا حصر لها تقريبًا.
تقع على عاتق المبرمج مسؤولية مراجعة مواصفات اللغة لتجنب كتابة برامج غير سليمة، حيث قد تتغير دلالاتها نتيجةً لأي تحسين قانوني يُجريه المُترجم. وتُلقي لغة فورتران تقليديًا عبئًا كبيرًا على المبرمج ليكون على دراية بهذه المشكلات، ولا تتخلف عنها كثيرًا لغات برمجة الأنظمة C و C++.
تقوم بعض لغات البرمجة عالية المستوى بإلغاء هياكل المؤشرات تمامًا، حيث يعتبر هذا المستوى من اليقظة والاهتمام بالتفاصيل مرتفعًا للغاية بحيث لا يمكن الحفاظ عليه بشكل موثوق حتى بين المبرمجين المحترفين.
يُعتبر الإلمام الكامل بدلالات ترتيب الذاكرة تخصصًا دقيقًا حتى بين فئة مبرمجي الأنظمة المحترفين الذين يتمتعون عادةً بأفضل معرفة في هذا المجال. يكتفي معظم المبرمجين بفهم عملي كافٍ لهذه المسائل ضمن نطاق خبرتهم البرمجية المعتادة. أما في أقصى درجات التخصص في دلالات ترتيب الذاكرة، فيوجد المبرمجون الذين يصممون أطر عمل برمجية لدعم نماذج الحوسبة المتزامنة .
تداخل المتغيرات المحلية
لاحظ أنه لا يمكن افتراض أن المتغيرات المحلية خالية من التداخل إذا تسرب مؤشر إلى مثل هذا المتغير إلى النظام العام:
المجموع = f(&a) + g(a)؛
لا يمكن التنبؤ بما fقد تفعله الدالة بالمؤشر المُمرر إليها a، بما في ذلك ترك نسخة منه في الحالة العامة التي gتصل إليها الدالة لاحقًا. في أبسط الحالات، fتكتب الدالة قيمة جديدة للمتغير a، مما يجعل هذا التعبير غير مُعرَّف بشكل صحيح في ترتيب التنفيذ. fيمكن منع الدالة من فعل ذلك بشكل واضح عن طريق تطبيق مُحدِّد const على تعريف وسيط المؤشر، مما يجعل التعبير مُعرَّفًا بشكل صحيح. ولذلك، أصبحت ثقافة لغة C/C++ الحديثة مهووسة إلى حد ما بتوفير مُحدِّدات const لتعريفات وسائط الدوال في جميع الحالات الممكنة.
تسمح لغتا C و C++ بتحويل نوع السمة constness داخليًا fكإجراء خطير . إذا fكان هذا التحويل يؤدي إلى تعطيل التعبير المذكور أعلاه، فلا ينبغي تعريف نوع وسيط المؤشر على أنه const من الأساس.
تميل لغات البرمجة عالية المستوى الأخرى نحو سمة إعلان كهذه تصل إلى حد الضمان القوي الذي لا توجد فيه ثغرات لانتهاك هذا الضمان المقدم داخل اللغة نفسها؛ كل الرهانات على ضمان اللغة هذا لاغية إذا كان تطبيقك يربط مكتبة مكتوبة بلغة برمجة مختلفة (على الرغم من أن هذا يعتبر تصميمًا سيئًا للغاية).
تنفيذ حاجز الذاكرة في وقت الترجمة
تمنع هذه الحواجز المترجم من إعادة ترتيب التعليمات أثناء وقت الترجمة - فهي لا تمنع إعادة الترتيب بواسطة وحدة المعالجة المركزية أثناء وقت التشغيل.
- أي من عبارات التجميع المضمنة في GNU تمنع مترجم GCC من إعادة ترتيب أوامر القراءة والكتابة حولها: [ 9 ]
asm volatile("" ::: "memory"); __asm__ __volatile__ ("" ::: "memory");- تمنع هذه الدالة C11/C++11 المترجم من إعادة ترتيب أوامر القراءة والكتابة حولها: [ 10 ]
atomic_signal_fence(memory_order_acq_rel);
- يستخدم مُجمِّع Intel C++ (ICC/ICL) وظائف "السياج الكامل للمُجمِّع" الداخلية: [ 11 ] [ 12 ]
__memory_barrier()
- يدعم مُترجم Microsoft Visual C++ (MSVC) بعض الوظائف المضمنة فقط لـ x86/x64 (جميع هذه الوظائف مهملة): [ 13 ]
_ReadBarrier() _WriteBarrier() _ReadWriteBarrier()
الحواجز المشتركة
في العديد من لغات البرمجة، يمكن دمج أنواع مختلفة من الحواجز مع عمليات أخرى (مثل التحميل، والتخزين، والزيادة الذرية، والمقارنة الذرية، والتبديل)، لذا لا حاجة إلى حاجز ذاكرة إضافي قبلها أو بعدها (أو كليهما). وبحسب بنية وحدة المعالجة المركزية المستهدفة، تُترجم هذه البنى اللغوية إما إلى تعليمات خاصة، أو إلى تعليمات متعددة (مثل الحاجز والتحميل)، أو إلى تعليمات عادية، وذلك تبعًا لضمانات ترتيب الذاكرة في الجهاز.
ترتيب الذاكرة أثناء التشغيل
في أنظمة المعالجات الدقيقة متعددة المعالجة المتناظرة (SMP)
توجد عدة نماذج لتناسق الذاكرة لأنظمة المعالجة المتعددة المتناظرة (SMP) :
- الاتساق التسلسلي (جميع عمليات القراءة والكتابة تتم بالترتيب)
- اتساق مرن (يُسمح ببعض أنواع إعادة الترتيب)
- يمكن إعادة ترتيب عمليات التحميل بعد عمليات التحميل (لتحسين تماسك ذاكرة التخزين المؤقت، وتحسين قابلية التوسع).
- يمكن إعادة طلب الشحنات بعد وصولها إلى المتاجر
- يمكن إعادة ترتيب المتاجر بعد المتاجر
- يمكن إعادة ترتيب المتاجر بعد عمليات التحميل.
- اتساق ضعيف (يتم إعادة ترتيب عمليات القراءة والكتابة بشكل عشوائي، ولا يحدها سوى حواجز الذاكرة الصريحة )
في بعض وحدات المعالجة المركزية
- يمكن إعادة ترتيب العمليات الذرية باستخدام عمليات التحميل والتخزين. [ 14 ]
- قد يكون هناك مسار تخزين مؤقت للتعليمات غير متماسك، مما يمنع تنفيذ التعليمات البرمجية ذاتية التعديل بدون تعليمات خاصة لمسح/إعادة تحميل ذاكرة التخزين المؤقت للتعليمات.
- يمكن إعادة ترتيب عمليات التحميل التابعة (وهذه ميزة فريدة في معمارية ألفا). إذا قام المعالج أولاً بجلب مؤشر إلى بيانات معينة ثم جلب البيانات نفسها، فقد لا يجلب البيانات نفسها، بل يستخدم بيانات قديمة مخزنة مؤقتًا ولم يتم إبطالها بعد. يُسهّل هذا التيسير عملية التخزين المؤقت ويجعلها أسرع، ولكنه يستلزم وجود حواجز ذاكرة للقراء والكتاب. [ 15 ] في معمارية ألفا (مثل أنظمة ألفا 21264 متعددة المعالجات )، تتم معالجة عمليات إبطال أسطر التخزين المؤقت المرسلة إلى المعالجات الأخرى بشكل كسول افتراضيًا، ما لم يُطلب صراحةً معالجتها بين عمليات التحميل التابعة. كما تسمح مواصفات معمارية ألفا بأشكال أخرى من إعادة ترتيب عمليات التحميل التابعة، على سبيل المثال استخدام قراءات البيانات التخمينية قبل معرفة المؤشر الحقيقي المراد الوصول إليه.
| يكتب | ألفا | ARMv7 | نظام MIPS | RISC-V | PA-RISC | قوة | سبارك | x86 [ أ ] | AMD64 | IA-64 | z/Architecture | |||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| المنظمة العالمية للأرصاد الجوية | TSO | RMO | مكتب خدمات الشرطة | TSO | ||||||||||
| يمكن إعادة ترتيب الشحنات بعد الشحنات | Y | Y | يعتمد ذلك على التنفيذ | Y | Y | Y | Y | Y | ||||||
| يمكن إعادة طلب الشحنات بعد وصولها إلى المتاجر | Y | Y | Y | Y | Y | Y | Y | |||||||
| يمكن إعادة ترتيب المتاجر بعد المتاجر | Y | Y | Y | Y | Y | Y | Y | Y | ||||||
| يمكن إعادة ترتيب المتاجر بعد عمليات التحميل. | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | |
| يمكن إعادة ترتيب الذرات مع الأحمال | Y | Y | Y | Y | Y | Y | ||||||||
| يمكن إعادة طلب منتجات Atomic من المتاجر | Y | Y | Y | Y | Y | Y | Y | |||||||
| يمكن إعادة ترتيب الأحمال التابعة | Y | |||||||||||||
| ذاكرة تخزين مؤقتة/خط أنابيب تعليمات غير متماسكة | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | ||||
- نماذج ترتيب الذاكرة في RISC-V
- المنظمة العالمية للأرصاد الجوية
- ترتيب الذاكرة الضعيف (افتراضي)
- TSO
- إجمالي طلب المتجر (مدعوم فقط مع إضافة Ztso)
- أوضاع ترتيب الذاكرة في معالجات SPARC
- TSO
- إجمالي طلب المتجر (افتراضي)
- RMO
- ترتيب الذاكرة المرن (غير مدعوم على وحدات المعالجة المركزية الحديثة)
- مكتب خدمات الشرطة
- طلب جزئي من المتجر (غير مدعوم على وحدات المعالجة المركزية الحديثة)
تنفيذ حاجز ذاكرة الأجهزة
تحتوي العديد من البنى التي تدعم المعالجة المتعددة المتناظرة (SMP) على تعليمات خاصة للأجهزة لتفريغ عمليات القراءة والكتابة أثناء وقت التشغيل .
lfence (asm), void _mm_lfence(void) sfence (asm), void _mm_sfence(void) [ 18 ] mfence (asm), void _mm_mfence(void) [ 19 ]
مزامنة (asm)
sync (asm) [ 20 ] [ 21 ]
mf (asm)
dcs (asm)
dmb (asm) dsb (asm) isb (asm)
دعم المُترجم لحواجز ذاكرة الأجهزة
تدعم بعض المترجمات البرمجية وظائف مدمجة تُصدر تعليمات حاجز الذاكرة المادية:
- GCC ، [ 23 ] الإصدار 4.4.0 وما بعده، [ 24 ] لديه
__sync_synchronize. - تمت إضافة أمر منذ الإصدارين C11 و C++11 .
atomic_thread_fence() - يحتوي مُصرّف Microsoft Visual C++
MemoryBarrier()على ماكرو في رأس واجهة برمجة تطبيقات Windows (مهمل). [ 25 ] [ 13 ] - يحتوي برنامج Sun Studio Compiler Suite [ 26 ]
__machine_r_barrierعلى ،__machine_w_barrierو__machine_rw_barrier.
انظر أيضاً
مراجع
- 1 2 3 4 5 بريشينغ، جيف (30 سبتمبر 2012). "نماذج الذاكرة الضعيفة مقابل القوية" . بريشينغ في البرمجة . تم الاسترجاع في 3 أغسطس 2024 .
- 1 2 هاولز، ديفيد؛ ماكيني، بول إي؛ ديكون، ويل؛ زيلسترا، بيتر. "حواجز ذاكرة نواة لينكس" . أرشيف نواة لينكس . تم الاسترجاع في 3 أغسطس 2024 .
- ↑ بريشينغ، جيف (25 يونيو 2012). "ترتيب الذاكرة في وقت الترجمة" . بريشينغ في البرمجة . تم الاسترجاع في 3 أغسطس 2024 .
- 1 2 سيويل، بيتر. "التزامن في الذاكرة المريحة" . جامعة كامبريدج . تم الاسترجاع في 3 أغسطس 2024 .
- 1 2 3 4 5 ماكيني، بول إي (19 سبتمبر 2007). "ترتيب الذاكرة في المعالجات الدقيقة الحديثة" (ملف PDF) . تم الاطلاع عليه في 3 أغسطس 2024 .
- 1 2 تورفالدز، لينوس (8 ديسمبر 2003). "ردًا على: التنبؤ بالفروع، وإعادة التسمية، والوصلات" . تم الاطلاع عليه في 3 أغسطس 2024 .
- ↑ مانسون، جيريمي؛ غوتز، برايان (فبراير 2004). "أسئلة وأجوبة حول JSR 133 (نموذج ذاكرة جافا)" . جامعة ميريلاند . تم الاطلاع عليه في 3 أغسطس 2024 .
- ↑ "ورقة بيضاء حول ترتيب الذاكرة في معمارية إنتل 64" (ملف PDF) . إنتل . أغسطس 2007. تم الاطلاع عليه في 3 أغسطس 2024 .
- ↑ ملف GCC compiler-gcc.h مؤرشف بتاريخ 24 يوليو 2011 في أرشيف الإنترنت (Wayback Machine)
- ↑ "std::atomic_signal_fence" . ccpreference .
- ↑ ECC compiler-intel.h مؤرشف بتاريخ 24 يوليو 2011 في Wayback Machine
- ↑ مرجع وظائف مُصرّف Intel® C++ الداخلية
يُنشئ هذا حاجزًا يمنع المُصرّف من جدولة أي تعليمات للوصول إلى البيانات. يجوز للمُصرّف تخصيص بيانات محلية في السجلات عبر حاجز الذاكرة، ولكن ليس بيانات عامة.
- 1 2 "_ReadWriteBarrier" . مايكروسوفت ليرن . 3 أغسطس 2021.
- ↑ فيكتور أليساندري، 2015. برمجة تطبيقات الذاكرة المشتركة: مفاهيم واستراتيجيات في برمجة التطبيقات متعددة النوى. إلسيفير ساينس. ص 176. ISBN 978-0-12-803820-8.
- ↑ إعادة الترتيب على معالج ألفا بقلم كوروش جاراتشورلو
- ↑ ماكيني، بول إي (7 يونيو 2010). "حواجز الذاكرة: نظرة على الأجهزة لمخترقي البرامج" (ملف PDF) . ص 16. تم الاطلاع عليه في 3 أغسطس 2024 . الشكل 5.
- ↑ الجدول 1. ملخص ترتيب الذاكرة ، من "ترتيب الذاكرة في المعالجات الدقيقة الحديثة، الجزء الأول"
- ↑ سياج المتجر — سياج المتجر
- ↑ سياج الذاكرة — سياج الذاكرة
- ↑ "مواصفات بروتوكول التماسك MIPS®، المراجعة 01.01" (ملف PDF) . صفحة 26. تم الاطلاع عليه بتاريخ 15-12-2023 .
- ↑ "مجموعة تعليمات MIPS R5" (ملف PDF) . ص 59-60 . تم الاطلاع عليه بتاريخ 15-12-2023 .
- ↑ حاجز ذاكرة البيانات، وحاجز مزامنة البيانات، وحاجز مزامنة التعليمات.
- ↑ المكونات الذرية المدمجة
- ↑ "36793 – x86-64 لا يحصل على __sync_synchronize بشكل صحيح" .
- ↑ "دالة MemoryBarrier (winnt.h) - تطبيقات Win32" . مايكروسوفت ليرن . 6 أكتوبر 2021.
- ↑ معالجة ترتيب الذاكرة في التطبيقات متعددة الخيوط باستخدام Oracle Solaris Studio 12 Update 2: الجزء 2، حواجز الذاكرة وسياج الذاكرة
للمزيد من القراءة
- نماذج اتساق الذاكرة المشتركة: برنامج تعليمي لساريتا في أدفي وكوروش جاراتشورلو
- ترتيب الذاكرة في المعالجات الدقيقة الحديثة بقلم بول إي ماكيني
- نماذج الذاكرة الضعيفة مقابل نماذج الذاكرة القوية، بقلم جيف بريشينغ
- نموذج رسمي لترتيب الذاكرة الأساسية من قبل جايد ألغلاف وآخرون.
- ترتيب الذاكرة في معمارية إنتل (IA) على يوتيوب - محاضرة تقنية من جوجل يقدمها ريتشارد إل هدسون
- هندسة الحاسوب - منهج كمي . الطبعة الرابعة. ج. هينيسي، د. باترسون، 2007. الفصل 4.6
- هندسة الحاسوب
- ذاكرة الحاسوب
- نماذج الاتساق
- بناء المترجم
- تصميم لغات البرمجة
- أنظمة وقت التشغيل
- التزامن (علوم الحاسوب)
