هل هناك أي ميزة باستخدام الكلمة الرئيسية المتقلبة على النقيض من استخدام الفئة المتشابكة؟
-
19-09-2019 - |
سؤال
بمعنى آخر، هل يمكنني أن أفعل شيئا مع متغير متقلب لا يمكن حلها أيضا بمتغير عادي وفئة متشابكة؟
المحلول
تحرير: سؤال إعادة كتابة إلى حد كبير
للإجابة على هذا السؤال، قمت بتقسيم بعض الشيء في الأمر ووجدت بعض الأشياء حولها volatile
و Interlocked
أنني لم أكن على علم. دعونا نخلص ذلك، ليس فقط بالنسبة لي، ولكن بالنسبة لهذه المناقشة وغيرها من الأشخاص الذين يقرأون هذا:
volatile
من المفترض أن تكون القراءة / الكتابة محصنة لإعادة ترتيبها. هذه فقط يعني القراءة والكتابة، يفعل ليس يعني أي إجراء آخر؛- التقلب لا يتم إجباره على وحدة المعالجة المركزية، أي مستوى الأجهزة (X86 يستخدم الحصول على الأسوار وإطلاقها أي قراءة و كتابة). إنه يمنع تحسين التحويل البرمجي أو CLR؛
Interlocked
يستخدم تعليمات الجمعية الذرية للمقارنة (cmpxchg
)، زيادة راتب (inc
) إلخ؛Interlocked
هل الاستخدام قفل في بعض الأحيان: قفل الأجهزة على أنظمة المعالج المتعددة; ؛ في أنظمة معالج UNI، لا يوجد قفل للأجهزة؛Interlocked
يختلف عنvolatile
في ذلك يستخدم السياج الكامل, ، حيث يستخدم المتقلب نصف السياج.- يمكن إعادة ترتيب قراءة القراءة التالية عند استخدامها
volatile
. وبعد لا يمكن أن يحدث معInterlocked
.VolatileRead
وVolatileWrite
لديهم نفس القضية إعادة ترتيب مثل `متقلبة (رابط بفضل براين جيدون).
الآن لدينا القواعد، يمكننا تحديد إجابة على سؤالك:
- من الناحية الفنية: نعم، هناك أشياء يمكنك القيام بها
volatile
أنه لا يمكنك القيام بهInterlocked
:- بناء الجملة: لا يمكنك الكتابة
a = b
أينa
أوb
متقلب، ولكن هذا واضح؛ - يمكنك قراءة قيمة مختلفة بعد كتابةها إلى متغير متقلب بسبب إعادة ترتيب. لا يمكنك القيام بذلك
Interlocked
. وبعد بمعنى آخر: يمكنك أن تكون أقل آمنة معvolatile
ثم يمكنك أن تكون معInterlocked
. - أداء:
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 هو حاجز ذاكرة كاملا يمكن أن يوفر لك نفس خصائص المتغير المتقلب وكذلك العديد من الآخرين. كما قيل بالفعل مضطرب يضمن أنه في سيناريوهات متعددة الخيوط إذا تغير وحدة المعالجة المركزية قيمة في خط ذاكرة التخزين المؤقت لها، يرى وحدة المعالجة المركزية الأخرى القيمة على الفور ولكن لا تضمن أي قفل الدلالي على الإطلاق.
الشيء هو القفل هو أكثر قوة أكبر بكثير من المتقلب ويجب عليك استخدام متقلب عندكنك لتجنب الأقفال غير الضرورية.