سؤال

على معظم الأنظمة الأساسية الشائعة (أهمها x86؛أدرك أن بعض الأنظمة الأساسية لديها نماذج ذاكرة صعبة للغاية ولا توفر تقريبًا أي ضمانات مفيدة لتعدد مؤشرات الترابط، لكنني لا أهتم بالأمثلة المضادة النادرة)، هل التعليمة البرمجية التالية آمنة؟

الموضوع 1:

someVariable = doStuff();
atomicSet(stuffDoneFlag, 1);

الموضوع 2:

while(!atomicRead(stuffDoneFlag)) {}  // Wait for stuffDoneFlag to be set.
doMoreStuff(someVariable);

بافتراض التطبيقات القياسية والمعقولة للعمليات الذرية:

  1. هل تم تعيين الموضوع 1 إلى someVariable مضمونة لإكمال قبل atomicSet() يسمى؟
  2. هل الموضوع 2 مضمون لرؤية المهمة someVariable قبل الاتصال doMoreStuff() بشرط أن يقرأ stuffDoneFlag ذريا؟

التعديلات:

  1. يحتوي تطبيق العمليات الذرية الذي أستخدمه على الإصدار x86 LOCK instruction in each operation, if that helps.
  2. يفترض stuffDoneFlag يتم مسح بشكل صحيح بطريقة أو بأخرى.كيف ليس مهما.
  3. هذا مثال مبسط للغاية.لقد قمت بإنشائها بهذه الطريقة حتى لا تضطر إلى فهم سياق المشكلة بالكامل للإجابة عليها.أعلم أنها ليست فعالة.
هل كانت مفيدة؟

المحلول

إذا كان كود x86 الفعلي الخاص بك يحتوي على متجر someVariable قبل المتجر في atomicSet في Thread 1 وتحميل someVariable بعد التحميل في atomicRead في Thread 2، فيجب أن تكون على ما يرام. دليل مطور برامج إنتل، المجلد 3A يحدد نموذج الذاكرة لـ x86 في القسم 8.2، ويجب أن تكون قيود التخزين والتحميل داخل الخيط كافية هنا.

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

نصائح أخرى

1) نعم

2) نعم

كلا العملين.

يبدو هذا الرمز آمنًا، لكنني أشكك في كفاءة رمزك spinlock (الحلقة أثناء) إلا إذا كنت تدور لفترة قصيرة جدًا من الوقت.ليس هناك ما يضمن في أي نظام معين أن Thread 2 لن يستهلك وقت المعالجة بالكامل.

أوصي باستخدام بعض أساسيات المزامنة الفعلية (يبدو دفعة::condition_variable هو ما تريده هنا) بدلاً من الاعتماد على قفل الدوران.

تضمن التعليمات الذرية أن ينتظر الخيط 2 حتى يكمل الخيط 1 إعداد المتغير قبل متابعة الخيط 2.ومع ذلك، هناك مسألتان رئيسيتان:

1) ال someVariable يجب أن يعلن 'متقلب" للتأكد من أن المترجم لا يقوم بتحسين تخصيصه على سبيل المثال.تخزينه في سجل أو تأجيل الكتابة.

2) يتم حظر الخيط الثاني أثناء انتظار الإشارة (يسمى com.spinlocking).من المحتمل أن توفر منصتك أساسيات وآليات قفل وإشارة أفضل بكثير، ولكن التحسين المباشر نسبيًا سيكون ببساطة sleep() في الموضوع 2 while() جسم.

دسمشا مكتوب:"افترض أنه تم مسح stuffDoneFlag بشكل صحيح بطريقة أو بأخرى.كيف ليس مهما."هذا ليس صحيحا!

دعونا نرى السيناريو:

  1. يتحقق Thread2 من stuffDoneFlag إذا كان 1 يبدأ في قراءة someVariable.
  2. قبل انتهاء Thread2 من القراءة، يقوم برنامج جدولة المهام بمقاطعة مهمته وتعليق المهمة لبعض الوقت.
  3. يصل Thread1 مرة أخرى إلى someVariable ويغير محتوى الذاكرة.
  4. يتم تشغيل برنامج جدولة المهام Thread2 مرة أخرى ويستمر في المهمة ولكن تم تغيير محتوى الذاكرة الخاص بـ someVariable!
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top