هل هناك أي ميزة باستخدام الكلمة الرئيسية المتقلبة على النقيض من استخدام الفئة المتشابكة؟

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

سؤال

بمعنى آخر، هل يمكنني أن أفعل شيئا مع متغير متقلب لا يمكن حلها أيضا بمتغير عادي وفئة متشابكة؟

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

المحلول

تحرير: سؤال إعادة كتابة إلى حد كبير

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

  • volatile من المفترض أن تكون القراءة / الكتابة محصنة لإعادة ترتيبها. هذه فقط يعني القراءة والكتابة، يفعل ليس يعني أي إجراء آخر؛
  • التقلب لا يتم إجباره على وحدة المعالجة المركزية، أي مستوى الأجهزة (X86 يستخدم الحصول على الأسوار وإطلاقها أي قراءة و كتابة). إنه يمنع تحسين التحويل البرمجي أو CLR؛
  • Interlocked يستخدم تعليمات الجمعية الذرية للمقارنة (cmpxchg)، زيادة راتب (inc) إلخ؛
  • Interlocked هل الاستخدام قفل في بعض الأحيان: قفل الأجهزة على أنظمة المعالج المتعددة; ؛ في أنظمة معالج UNI، لا يوجد قفل للأجهزة؛
  • Interlocked يختلف عن volatile في ذلك يستخدم السياج الكامل, ، حيث يستخدم المتقلب نصف السياج.
  • يمكن إعادة ترتيب قراءة القراءة التالية عند استخدامها volatile. وبعد لا يمكن أن يحدث مع Interlocked. VolatileRead و VolatileWrite لديهم نفس القضية إعادة ترتيب مثل `متقلبة (رابط بفضل براين جيدون).

الآن لدينا القواعد، يمكننا تحديد إجابة على سؤالك:

  • من الناحية الفنية: نعم، هناك أشياء يمكنك القيام بها volatile أنه لا يمكنك القيام به Interlocked:
    1. بناء الجملة: لا يمكنك الكتابة a = b أين a أو b متقلب، ولكن هذا واضح؛
    2. يمكنك قراءة قيمة مختلفة بعد كتابةها إلى متغير متقلب بسبب إعادة ترتيب. لا يمكنك القيام بذلك Interlocked. وبعد بمعنى آخر: يمكنك أن تكون أقل آمنة مع volatile ثم يمكنك أن تكون مع Interlocked.
    3. أداء: volatile هو أسرع ثم Interlocked.
  • semantically: لا، لأن Interlocked ما عليك سوى توفير استبعاد العمليات وهو أكثر أمانا للاستخدام لأنه ينطبق على المبارزة الكاملة. لا يمكنك أن تفعل أي شيء مع volatile أنه لا يمكنك القيام به Interlocked ويمكنك القيام به كثير مع Interlocked لا يمكنك القيام به مع المتقلب:

    static volatile int x = 0;
    x++;                        // non-atomic
    static int y = 0;
    Interlocked.Increment(y);   // atomic
    
  • النطاق: نعم، أعلن متغير volatile يجعلها متقلبة لكل وصول واحد. من المستحيل إجبار هذا السلوك بأي طريقة أخرى، وبالتالي volatile لا يمكن استبداله Interlocked. وبعد هناك حاجة إلى ذلك في السيناريوهات حيث يمكن للمكتبات أو الواجهات أو الأجهزة الوصول إلى المتغير وتحديثها في أي وقت، أو تحتاج إلى أحدث إصدار.

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


تحرير: كان الاقتباس التالي جزءا من إجابتي الأصلية، سأتركه في ؛-)

اقتباس من ج # لغة البرمجة اساسي:

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

  • يسمى قراءة حقل مضطرب قراءة متقلبة. وبعد قراءة متقلبة: اكتساب دلالات "؛ وهذا هو، مضمون حدوثه قبل أي مراجع إلى الذاكرة التي تحدث بعد ذلك في تسلسل التعليمات.

  • يسمى الكتابة من حقل متقلب متقلب الكتابة. وبعد يحتوي الكتابة المتقلبة على "الإفراج عن دلالات"؛ أي أنه مضمون أن يحدث بعد أي مراجع ذاكرة قبل تعليمات الكتابة في تسلسل التعليمات.

تحديث: سؤال إعادة كتابة إلى حد كبير، وصحبت ردي الأصلي وأضاف إجابة "حقيقية"

نصائح أخرى

هذا هو موضوع معقد إلى حد ما. أجد جوزيف البحري وضع أن تكون واحدة من المصادر الأكثر نهائيا ودقيقة لمفاهيم متعددة التوالي في .NET Framework والتي قد تساعد في الإجابة على سؤالك.

ولكن، يلخص بسرعة هناك الكثير من التداخل بين volatile الكلمة الرئيسية و Interlocked فئة بقدر ما يمكن استخدامه. وبالطبع يتجول كلاهما فوق وما يمكنك القيام به بمتغير عادي.

نعم - يمكنك أن تنظر إلى القيمة مباشرة.

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

يأخذ هذه الحلقة:

bool done = false;

...

while(!done)
{
... do stuff which the compiler can prove doesn't touch done...
}

إذا قمت بتعيين done ل true في مؤشر ترابط آخر سوف تتوقع الخروج من الحلقة. ومع ذلك - إذا تم القيام به غير ملحوظ volatile ثم يحتوي المحول البرمجي على خيار تحقيق أن رمز الحلقة لا يمكن أن يتغير أبدا done ويمكن أن يحسن القارن للخروج.

هذه هي واحدة من الأشياء الصعبة حول البرمجة المتعددة - العديد من المواقف التي تعتبر مشاكل تأتي فقط في بعض المواقف.

لن أحاول أن أكون سلطة حول هذا الموضوع ولكني أوصي بشدة بإلقاء نظرة على هذه المقالة بواسطة jon jon skeet.

إلقاء نظرة أيضا على الجزء الأخير من هذه الإجابة التي تفاصيل ماذا volatile يجب أن تستخدم ل.

نعم، يمكنك الحصول على بعض الأداء باستخدام متغير متقلب بدلا من قفل.

Lock هو حاجز ذاكرة كاملا يمكن أن يوفر لك نفس خصائص المتغير المتقلب وكذلك العديد من الآخرين. كما قيل بالفعل مضطرب يضمن أنه في سيناريوهات متعددة الخيوط إذا تغير وحدة المعالجة المركزية قيمة في خط ذاكرة التخزين المؤقت لها، يرى وحدة المعالجة المركزية الأخرى القيمة على الفور ولكن لا تضمن أي قفل الدلالي على الإطلاق.

الشيء هو القفل هو أكثر قوة أكبر بكثير من المتقلب ويجب عليك استخدام متقلب عندكنك لتجنب الأقفال غير الضرورية.

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