سؤال

في خدمة الويب الخاصة بـ ASMX Multisted ، كان لدي حقل دراسي _alldata من النوع الخاص بي SystemData الذي يتكون من عدد قليل List<T> و Dictionary<T> تحمل علامة volatile. بيانات النظام (_allData) تم تحديثها من حين لآخر وأنا أفعل ذلك عن طريق إنشاء كائن آخر يسمى newData وملء هياكل البيانات مع بيانات جديدة. عندما يتم ذلك ، أخصص فقط

private static volatile SystemData _allData

public static bool LoadAllSystemData()
{
    SystemData newData = new SystemData();
    /* fill newData with up-to-date data*/
     ...
    _allData = newData.
} 

يجب أن ينجح هذا لأن المهمة ذرية وأن مؤشرات الترابط التي لديها الإشارة إلى البيانات القديمة تستمر في استخدامها والباقي لديها بيانات النظام الجديدة بعد التخصيص مباشرة. ومع ذلك قال زعيمي إنه بدلاً من الاستخدام volatile الكلمة الرئيسية والاعتداء البسيط يجب أن أستخدمه InterLocked.Exchange لأنه قال إنه على بعض المنصات ، لا يضمن أن المهمة المرجعية ذرية. علاوة على ذلك: عندما أعلن the _allData الحقل كما volatile ال

Interlocked.Exchange<SystemData>(ref _allData, newData); 

ينتج تحذير "إشارة إلى مجال متقلبة لن يتم التعامل معها على أنها متقلبة" ماذا يجب أن أفكر في هذا؟

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

المحلول

هناك العديد من الأسئلة هنا. النظر فيها واحد في وقت واحد:

المهمة المرجعية ذرية فلماذا متشابك.

المهمة المرجعية ذرية. interlocked.exchange لا يقوم فقط بالتعيين المرجعي. إنها تقرأ القيمة الحالية للمتغير ، وتخبأ القيمة القديمة ، ويعين القيمة الجديدة للمتغير ، كل ذلك كعملية ذرية.

قال زميلي إنه على بعض المنصات ، لا يضمن أن المهمة المرجعية ذرية. هل كان زميلي صحيحًا؟

لا. يضمن التخصيص المرجعي أن يكون ذريًا على جميع منصات .NET.

زميلي هو التفكير من المباني الخاطئة. هل هذا يعني أن استنتاجاتهم غير صحيحة؟

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

ينتج تحذير "إشارة إلى مجال متقلبة لن يتم التعامل معها على أنها متقلبة" ماذا يجب أن أفكر في هذا؟

يجب أن تفهم لماذا هذه مشكلة بشكل عام. سيؤدي ذلك إلى فهم سبب عدم أهمية التحذير في هذه الحالة بالذات.

السبب في أن المترجم يعطي هذا التحذير هو أن وضع علامة على الحقل يعني أن "هذا الحقل سيتم تحديثه على مؤشرات ترابط متعددة - لا تنشئ أي رمز يقوم بتخزين قيم هذا الحقل ، والتأكد من أن أي قراءة أو يكتب من لا يتم نقل هذا الحقل إلى الأمام والخلف في الوقت المناسب "عبر تناقضات ذاكرة التخزين المؤقت المعالج".

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

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

لذلك ، يحذر المترجم عند القيام بذلك ، لأنه من المحتمل أن يعبث تمامًا منطقك الخالي من القفل المطور بعناية.

بالطبع ، interlocked.exchange هو مكتوبة لتوقع حقل متقلبة والقيام بالشيء الصحيح. التحذير بالتالي مضللة. يؤسفني هذا كثيرًا. ما كان يجب أن نفعله هو تنفيذ بعض الآليات التي يكون بموجبها مؤلف لطريقة مثل entroloced. ربما في نسخة مستقبلية من المترجم سنفعل ذلك.

نصائح أخرى

إما أن يكون زميلك مخطئًا ، أو أنه يعرف شيئًا لا يوجد فيه مواصفات لغة C#.

5.5 ذرية المراجع المتغيرة:

"يقرأ ويكتب أنواع البيانات التالية ذرية: Bool ، Char ، Byte ، Sbyte ، Short ، Ushort ، Uint ، Int ، Float ، and Reference Types."

لذلك ، يمكنك الكتابة إلى المرجع المتقلبة دون خطر الحصول على قيمة تالفة.

يجب أن تكون حذراً بالطبع في كيفية تحديد الخيط الذي يجب أن يجلب البيانات الجديدة ، لتقليل المخاطر التي يقوم بها أكثر من مؤشر ترابط في كل مرة.

interlocked.exchange <T>

يعين متغير من النوع T المحدد على قيمة محددة ويعيد القيمة الأصلية ، كعملية ذرية.

إنه يتغير ويعيد القيمة الأصلية ، إنها عديمة الفائدة لأنك تريد فقط تغييرها ، وكما قال قفا ، إنها بالفعل ذرية.

ما لم يثبت أحد البروفيلين أنه عنق الزجاجة في طلبك ، فيجب عليك التفكير في الأقفال غير المتوفرة ، فمن الأسهل فهم وإثبات أن الكود الخاص بك صحيح.

Iterlocked.Exchange() ليس ذريًا فحسب ، بل يعتني أيضًا برؤية الذاكرة:

تستخدم وظائف التزامن التالية الحواجز المناسبة لضمان ترتيب الذاكرة:

الوظائف التي تدخل أو تترك أقسام حرجة

الوظائف التي تشير إلى كائنات التزامن

وظائف الانتظار

وظائف متشابكة

قضايا التزامن والمعالجة المتعددة

هذا يعني أنه بالإضافة إلى الذرة ، يضمن ذلك:

  • للخيط الذي يطلق عليه:
    • لا يتم إعادة ترتيب التعليمات (بواسطة المترجم أو وقت التشغيل أو الأجهزة).
  • لجميع المواضيع:
    • لا تقرأ على الذاكرة التي تحدث قبل أن ترى هذه التعليمات التغيير التي تم إجراؤها.
    • جميع القراءات بعد هذه التعليمات ستشاهد التغيير الذي تم إجراؤه بواسطة هذه التعليمات.
    • ستحدث جميع الكتابة إلى الذاكرة بعد حدوث هذه التعليمات بعد أن وصل تغيير التعليمات هذه إلى الذاكرة الرئيسية (عن طريق مسح هذا التغيير إلى الذاكرة الرئيسية عند القيام به وعدم السماح للأجهزة بتدفقها على توقيتها).
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top