سؤال

لقد قمت بإبرام Spinlock بسيطا جدا باستخدام الوظائف المتشابكة في Windows واختبارها في وحدة المعالجة المركزية ثنائية النواة (مؤشر ترابط ثنائي النواة (مؤشران تزايد متغير)؛

يبدو أن البرنامج يعمل موافق (يعطي نفس النتيجة في كل مرة، وهذا ليس هو الحال عند استخدام أي مزامنة)، ولكن إنتل الموازي المفتش يقول أن هناك حالة سباق في القيمة + = J (انظر الكود أدناه). يختفي التحذير عند استخدام الأقسام الحرجة بدلا من Spinlock.

هل تنفيذي من Spinlock صحيح أم لا؟ من الغريب حقا، لأن جميع العمليات المستخدمة هي ذرية ولها حواجز الذاكرة المناسبة ولا ينبغي أن تؤدي إلى ظروف السباق.

class SpinLock
{
   int *lockValue;
   SpinLock(int *value) : lockValue(value) { }

   void Lock() {
      while(InterlockedCompareExchange((volatile LONG*)lockValue, 1, 0) != 0) {
          WaitABit();
      }
   }

   void Unlock() { InterlockedExchange((volatile LONG*)lockValue, 0); }
};

برنامج الاختبار:

static const int THREADS = 2;
HANDLE completedEvents[THREADS];
int value = 0;
int lock = 0; // Global.

DWORD WINAPI TestThread(void *param) {
    HANDLE completed = (HANDLE)param;
    SpinLock testLock(&lock);

    for(int i = 0;i < 1000*20; i++) {
        for(int j = 0;j < 10*10; j++) {
            // Add something to the variable.
            testLock.Lock();
            value += j;
            testLock.Unlock();
        }
    }
    SetEvent(completed);
}

int main() {
   for(int i = 0; i < THREADS; i++) {
        completedEvents[i] = CreateEvent(NULL, true, false, NULL);
   }
   for(int i = 0; i < THREADS; i++) {
        DWORD id;
        CreateThread(NULL, 0, TestThread, completedEvents[i], 0, &id);
   }

   WaitForMultipleObjects(THREADS, completedEvents, true, INFINITE);
   cout<<value;
}
هل كانت مفيدة؟

المحلول

وثائق المفتش الموازية ل سباق البيانات يقترح استخدام قسم حرج أو mutex لإصلاح السباقات على ويندوز. لا يوجد شيء يقترحه أن المفتش الموازي يعرف كيفية التعرف على أي آلية قفل أخرى قد تخترعها.

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

إذا كنت ترغب في تجربة آليات قفل جديدة، فإن الأداة الأكثر شيوعا التي رأيتها تستخدم في الأدب الأكاديمي تدور نموذج المدقق. وبعد هناك ايضا esp., ، والتي قد تقلل من مساحة الدولة، لكنني لا أعرف ما إذا كان قد تم تطبيقه على مشاكل متزامنة، وكذلك تنقل المنضدة والتي من شأنها أن تعطي تحليلا إذا كنت تستطيع الأريكة مشكلتك في PI-Calculus. لا يبدو مفتش Intel Parallel أي شيء مثل معقدة مثل هذه الأدوات، بل مصمم إلى حد ما للتحقق من المشكلات التي تحدث عادة باستخدام الاستدلال.

نصائح أخرى

بالنسبة للأشخاص الفقراء الآخرين في حالة مماثلة لي: توفر Intel مجموعة من الأنطات ويشمل المكتبات للقيام بهذا النوع من الأشياء بالضبط. تحقق في دليل تثبيت المفتش (سترى تضمينها، Lib32 و Lib64 في دليل التثبيت) لتلك المواد. وثائق حول كيفية استخدامها (اعتبارا من يونيو 2018، على الرغم من أن Intel لا يهتم بأي شيء حول حفظ الروابط ثابتا):

https://software.intel.com/en-us/inspector-user-guide-windows-apis-for-custom-synchronization.

هناك 3 وظائف:

void __itt_sync_acquired(void *addr)
void __itt_sync_releasing(void *addr)
void __itt_sync_destroy(void *addr)

أنا متأكد من أنه يجب تنفيذها على النحو التالي:

class SpinLock
{
   long lockValue;
   SpinLock(long value) : lockValue(value) { }

   void Lock() {
      while(InterlockedCompareExchange(&lockValue, 1, 0) != 0) {
          WaitABit();
      }
   }

   void Unlock() { InterlockedExchange(&lockValue, 0); }
};
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top