.NET Memory Model ، المتغيرات المتقلبة ، واختبار واختبار: ما هو مضمون؟

StackOverflow https://stackoverflow.com/questions/2099711

سؤال

أعلم أن نموذج ذاكرة .NET (على إطار .NET ؛ غير مضغوط/micro/silverlight/mono/xna/what-have-you) مضمون أن تكون عمليات معينة (وأبرزها أعرب عامية ومراجع) مضمونة الذري.

علاوة على ذلك ، أعتقد أن تعليمات الاختبار والمجموعة X86/X64 (و Interlocked.CompareExchange) في الواقع يشير إلى موقع الذاكرة العالمي ، لذلك إذا نجحت Interlocked.CompareExchange سترى القيمة الجديدة.

أخيرًا ، أعتقد أن volatile الكلمة الرئيسية هي تعليمات إلى المترجم لنشر القراءات والكتابة في أسرع وقت ممكن وعدم إعادة ترتيب العمليات المتعلقة بهذا المتغير (أليس كذلك؟).

هذا يؤدي إلى بعض الأسئلة:

  1. هل معتقداتي أعلاه صحيحة؟
  2. Interlocked.Read ليس لديه تحميل زائد لـ int ، فقط للطول (وهما كلمتين وبالتالي لا يتم قراءته بشكل ذري عادة). لقد افترضت دائمًا أن نموذج ذاكرة .NET يضمن أن أحدث قيمة ستظهر عند قراءة ints/المراجع ، ولكن مع ذاكرة التخزين المؤقت للمعالج ، والسجلات ، وما إلى ذلك. لقد بدأت في رؤية هذا قد لا يكون ممكنًا. فهل هناك طريقة لإجبار المتغير على إعادة إحصاء؟
  3. هل التقلب كافٍ لحل المشكلة أعلاه للأعداد الصحيحة والمراجع؟
  4. في x86/x64 هل يمكنني افتراض ...

إذا كان هناك اثنين من متغيرات عدد صحيح عالمي x و y ، كلاهما تم تهيئته إلى 0 أنه إذا كتبت:

x = 1;
y = 2;

لن يرى أي مؤشر ترابط x = 0 و y = 2 (أي أن الكتابة ستحدث بالترتيب). هل هذا التغيير إذا كانت متقلبة؟

هل كانت مفيدة؟

المحلول

  • تقرأ فقط ويكتب إلى المتغيرات التي يبلغ عرضها 32 بت على الأكثر (وعرضها 64 بت على أنظمة X64) ذرية. كل هذا يعني أنك لن تقرأ int واحصل على قيمة نصف مكتوب. هذا لا يعني الحساب ذري.
  • تعمل العمليات المتشابكة أيضًا كحواجز للذاكرة ، لذا نعم ، Interlocked.CompareExchange سوف نرى القيمة المحدثة.
  • يرى هذه الصفحة. التقلب لا يعني أمر. قد يختار بعض المترجمين عدم إعادة ترتيب العمليات على المتغيرات المتقلبة ، ولكن وحدة المعالجة المركزية مجانية في إعادة الطلب. إذا كنت ترغب في إيقاف وحدة المعالجة المركزية من إعادة الطلب ، فاستخدم حاجز ذاكرة (كامل).
  • يضمن نموذج الذاكرة أن القراءات والكتابة هي ذرية ، ويضمن استخدام الكلمة الرئيسية المتطايرة أن القراء دائماً تأتي من الذاكرة ، وليس من السجل. وانت ايضا إرادة انظر أحدث قيمة. هذا لأن وحدة المعالجة المركزية x86 ستقوم بإبطال ذاكرة التخزين المؤقت عند الاقتضاء - انظر هذه و هذه. انظر أيضا interlockedcompareexchange64 لكيفية قراءة قيم 64 بت من الناحية الذرية.
  • وأخيرا ، السؤال الأخير. الجواب هو موضوع يمكن أن يرى في الواقع x = 0 و y = 2, ، واستخدام الكلمة الرئيسية المتطايرة لا يغير ذلك لأن وحدة المعالجة المركزية مجانية في إعادة الطلب. تحتاج إلى حاجز الذاكرة.

ملخص:

  1. التحويل البرمجي مجاني لإعادة ترتيب التعليمات.
  2. وحدة المعالجة المركزية مجانية لإعادة ترتيب التعليمات.
  3. القراءات والكتابة بحجم الكلمات ذرية. العمليات الحسابية والعمليات الأخرى ليست ذرية لأنها تنطوي على قراءة ، حساب ، ثم الكتابة.
  4. ستقوم القراءات بحجم الكلمات من الذاكرة دائمًا إلى استرداد أحدث قيمة. لكن في معظم الأوقات لا تعرف ما إذا كنت تقرأ بالفعل من الذاكرة.
  5. يتوقف حاجز الذاكرة الكامل (1) و (2). يسمح لك معظم المترجمين بالتوقف (1) بمفرده.
  6. تضمن الكلمة الرئيسية المتطايرة أنك تقرأ من الذاكرة - (4).
  7. تتيح العمليات المتشابكة (بادئة القفل) أن تكون عمليات متعددة ذرية. على سبيل المثال ، قراءة + كتابة (interlockedExchange). أو قراءة + مقارنة + الكتابة (interlockedCompareexChange). كما أنها تعمل كحواجز للذاكرة ، لذلك (1) و (2) يتم إيقافها. يكتبون دائمًا إلى الذاكرة (من الواضح) ، لذلك (4) مضمون.

نصائح أخرى

جاء عبر هذا الموضوع القديم. الإجابات من Hans و WJ32 كلها صحيحة باستثناء الجزء المتعلق volatile.

على وجه التحديد فيما يتعلق بسؤالك

في x86/x64 ، هل يمكنني افتراض أن ... إذا كان هناك متغيران عدد صحيح عالمي X و Y ، وكلاهما تم تهيئته إلى 0 أنه إذا كتبت: x = 1; y = 2;

لن يرى أي مؤشر ترابط x = 0 و y = 2 (أي أن الكتابة ستحدث بالترتيب). هل هذا التغيير إذا كانت متقلبة؟

لو y متقلبة ، الكتابة إلى x هو ضمان أن يحدث قبل الكتابة إلى y, لذلك لن يرى أي موضوع على الإطلاق x = 0 و y = 2. ذلك لأن الكتابة إلى متغير متقلبة تحتوي على "إصدار الدلالي" (أي ما يعادل منطقيًا لانبعاث سياج الإصدار) ، أي جميع تعليمات القراءة/الكتابة قبل عدم تحريكها. (هذا يعني أنه إذا كان X متقلبة ولكن Y ليس كذلك ، فقد لا تزال ترى ما هو غير متوقع x = 0 و y = 2.) انظر مثال الوصف والرمز في C# المواصفات لمزيد من التفاصيل.

لا ، الكلمة الرئيسية المتطايرة وضمان الذرة ضعيفة للغاية. تحتاج إلى حاجز الذاكرة لضمان ذلك. يمكنك الحصول على واحدة بشكل صريح مع thread.memorybarrier ().

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