سؤال

لدي كائنات وظيفية صغيرة ولكنها مستخدمة بشكل متكرر.كل موضوع يحصل على نسخته الخاصة.يتم تخصيص كل شيء بشكل ثابت.لا تشارك النسخ أي بيانات عامة أو ثابتة.هل أحتاج إلى حماية هذه الكائنات من المشاركة الزائفة؟

شكرًا لك.يحرر:إليك برنامج ألعاب يستخدم Boost.Threads.هل يمكن أن تحدث مشاركة خاطئة للحقل بيانات?

#include <boost/thread/thread.hpp>

struct Work {
    void operator()() {
        ++data;
    }

    int data;
};

int main() {
    boost::thread_group threads;
    for (int i = 0; i < 10; ++i)
        threads.create_thread(Work());
    threads.join_all();
}
هل كانت مفيدة؟

المحلول

المشاركة الخاطئة بين سلاسل الرسائل هي عندما يستخدم خيطان أو أكثر نفس سطر ذاكرة التخزين المؤقت.

على سبيل المثال:

struct Work {
    Work( int& d) : data( d ) {}
    void operator()() {
        ++data;
    }

    int& data;
};

int main() {
    int false_sharing[10] = { 0 };
    boost::thread_group threads;
    for (int i = 0; i < 10; ++i)
        threads.create_thread(Work(false_sharing[i]));
    threads.join_all();

    int no_false_sharing[10 * CACHELINE_SIZE_INTS] = { 0 };
    for (int i = 0; i < 10; ++i)
        threads.create_thread(Work(no_false_sharing[i * CACHELINE_SIZE_INTS]));
    threads.join_all();
}

المواضيع في الكتلة الأولى تعاني من المشاركة الخاطئة.المواضيع في الكتلة الثانية لا (بفضل CACHELINE_SIZE).

تكون البيانات الموجودة على المكدس دائمًا "بعيدة" عن سلاسل الرسائل الأخرى.(على سبيل المثال.تحت النوافذ، على الأقل بضع صفحات).

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

وهذا قد يؤدي إلى عدة Work تكون المثيلات متجاورة وبالتالي قد تتطلب مشاركة خطوط ذاكرة التخزين المؤقت.

لكن ...عينتك غير منطقية، لأنه لا يتم المساس بالبيانات من الخارج مطلقًا، وبالتالي يتم التسبب في مشاركة زائفة دون داع.

الطريقة الأسهل، لمنع مثل هذه المشاكل، هي نسخ بياناتك "المشتركة" محليًا على المكدس، ثم العمل على نسخة المكدس.عند الانتهاء من عملك، قم بنسخه مرة أخرى إلى ملف الإخراج var.

على سبيل المثال:

struct Work {
    Work( int& d) : data( d ) {}
    void operator()()
    {
        int tmp = data;
        for( int i = 0; i < lengthy_op; ++i )
           ++tmp;
        data = tmp;
    }

    int& data;
};

وهذا يمنع كافة المشاكل المتعلقة بالمشاركة.

نصائح أخرى

لقد أجريت قدرًا لا بأس به من البحث ويبدو أنه لا يوجد حل سحري للمشاركة الزائفة.إليكم ما توصلت إليه (بفضل كريستوفر):1) قم بحشو بياناتك من كلا الجانبين بأشياء غير مستخدمة أو أقل استخدامًا.2) انسخ بياناتك إلى المكدس وانسخها مرة أخرى بعد الانتهاء من كل العمل الشاق.3) استخدم تخصيص الذاكرة المحاذاة لذاكرة التخزين المؤقت.

لا أشعر بالأمان التام تجاه التفاصيل، لكن إليكم وجهة نظري:

(1) مثالك المبسط معطل منذ التعزيز create_thread تتوقع إشارة، قمت بتمرير مؤقت.

(2) إذا كنت تستخدم vector<Work> مع وجود عنصر واحد لكل سلسلة رسائل، أو الاحتفاظ بها في الذاكرة بشكل تسلسلي، ستحدث مشاركة خاطئة.

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