كيف يمكنني إنشاء مؤشر الترابط-الآمن نمط المفرد في ويندوز ؟

StackOverflow https://stackoverflow.com/questions/164496

  •  03-07-2019
  •  | 
  •  

سؤال

كنت أقرأ عن موضوع آمن المفرد أنماط هنا:

http://en.wikipedia.org/wiki/Singleton_pattern#C.2B.2B_.28using_pthreads.29

وهو يقول في الجزء السفلي أن السبيل الوحيد الآمن هو استخدام pthread_once - التي لا تتوفر على نظام التشغيل ويندوز.

هو أن فقط طريقة لضمان الآمن موضوع initialisation?

لقد قرأت هذا الموضوع على ذلك:

موضوع آمنة كسول بناء المفرد في C++

و يبدو أن تلمح في ذرية مستوى نظام التشغيل مبادلة مقارنة الوظيفة التي أفترض على ويندوز:

http://msdn.microsoft.com/en-us/library/ms683568.aspx

وهذا يمكن أن أفعل ما أريد ؟

تحرير: أود كسول initialisation و هناك فقط من أي وقت مضى أن حالة واحدة من فئة.

شخص في موقع آخر ذكر استخدام العالمية داخل مساحة اسم (ووصف المفرد كما مضاد نمط) - كيف يمكن أن تكون "مكافحة نمط"?

الإجابة المقبولة:
لقد قبلت جوش الجواب كما أنا باستخدام Visual Studio 2008 - NB:المستقبل القراء ، إذا كنت لا تستخدم هذا المترجم (أو 2005) - لا تستخدم قبول الإجابة!!

تحرير: الكود يعمل بشكل جيد باستثناء عودة البيان - أحصل على خطأ:خطأ C2440:'عودة' :لا يمكن التحويل من 'متقلبة المفرد *' إلى 'المفرد *'.يجب تعديل قيمة الإرجاع إلى أن تكون متقلبة المفرد *?

تحرير: على ما يبدو const_cast<> إزالة متقلبة تصفيات.شكرا مرة أخرى إلى جوش.

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

المحلول

إذا كنت تستخدم Visual C++ 2005/2008 يمكنك استخدام مزدوج التحقق من قفل النمط, منذ "متقلبة المتغيرات تتصرف كما الأسوار".هذه هي الطريقة الأكثر فعالية لتنفيذ كسول-تهيئة المفرد.

من MSDN مجلة:

Singleton* GetSingleton()
{
    volatile static Singleton* pSingleton = 0;

    if (pSingleton == NULL)
    {
        EnterCriticalSection(&cs);

        if (pSingleton == NULL)
        {
            try
            {
                pSingleton = new Singleton();
            }
            catch (...)
            {
                // Something went wrong.
            }
        }

        LeaveCriticalSection(&cs);
    }

    return const_cast<Singleton*>(pSingleton);
}

كلما كنت بحاجة إلى الوصول إلى المفرد فقط اتصل GetSingleton().المرة الأولى ويسمى ثابت المؤشر سيتم تهيئة.بعد تهيئة فارغة التحقق من شأنها منع قفل لمجرد قراءة المؤشر.

لا استخدام هذا على أي مترجم, كما انها ليست المحمولة.المعيار يجعل أي ضمانات بشأن كيف سيكون هذا العمل.Visual C++ 2005 صراحة يضيف إلى دلالات متقلبة لجعل هذا ممكنا.

عليك أن تعلن ، تهيئة مقطع حرج في مكان آخر في التعليمات البرمجية.ولكن هذا التهيئة رخيص, كسول جدا التهيئة عادة ما يكون غير مهم.

نصائح أخرى

طريقة بسيطة لضمان عبر منصة موضوع آمنة التهيئة المفرد هو لأداء ذلك صراحة (عبر مكالمة عضو ثابت الدالة على المفرد) في الموضوع الرئيسي من التطبيق الخاص بك قبل التطبيق الخاص بك يبدأ في أي من المواضيع الأخرى (أو على الأقل أي من المواضيع الأخرى التي سيتم الوصول إلى المفرد).

ضمان موضوع الوصول الآمن إلى المفرد ثم يتحقق بالطريقة المعتادة مع mutexes/المقاطع الحرجة.

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

// A critical section guard - create on the stack to provide 
// automatic locking/unlocking even in the face of uncaught exceptions
class Guard {
    private:
        LPCRITICAL_SECTION CriticalSection;

    public:
        Guard(LPCRITICAL_SECTION CS) : CriticalSection(CS) {
            EnterCriticalSection(CriticalSection);
        }

        ~Guard() {
            LeaveCriticalSection(CriticalSection);
        }
};

// A thread-safe singleton
class Singleton {
    private:
        static Singleton* Instance;
        static CRITICAL_SECTION InitLock;
        CRITICIAL_SECTION InstanceLock;

        Singleton() {
            // Time consuming initialization here ...

            InitializeCriticalSection(&InstanceLock);
        }

        ~Singleton() {
            DeleteCriticalSection(&InstanceLock);
        }

    public:
        // Not thread-safe - to be called from the main application thread
        static void Create() {
            InitializeCriticalSection(&InitLock);
            Instance = NULL;
        }

        // Not thread-safe - to be called from the main application thread
        static void Destroy() {
            delete Instance;
            DeleteCriticalSection(&InitLock);
        }

        // Thread-safe lazy initializer
        static Singleton* GetInstance() {
            Guard(&InitLock);

            if (Instance == NULL) {
                Instance = new Singleton;
            }

            return Instance;
        }

        // Thread-safe operation
        void doThreadSafeOperation() {
            Guard(&InstanceLock);

            // Perform thread-safe operation
        }
};

ومع ذلك ، هناك أسباب جيدة لتجنب استخدام ووحدانية تماما (و لماذا هم في بعض الأحيان يشار إليه مكافحة نمط):

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

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

بينما أنا أحب الحل المقبول ، أنا فقط وجدت آخر خيط و فكرت أن حصة هنا: مرة واحدة التهيئة (ويندوز)

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

هناك توضيح النقطة تحتاج إلى النظر في هذه المسألة.هل تتطلب ...

  1. أن حالة واحدة فقط من فئة أي وقت مضى في الواقع خلق
  2. العديد من حالات فئة يمكن إنشاؤها ولكن لا ينبغي أن يكون واحد فقط صحيح نهائي مثيل من فئة

هناك العديد من العينات على شبكة الإنترنت لتنفيذ هذه الأنماط في C++.هنا رمز المشروع عينة

يوضح ما يلي كيفية القيام بذلك في C#, لكن نفس المفهوم ينطبق على أي لغة البرمجة التي من شأنها أن تدعم نمط سينغلتون

http://www.yoda.arachsys.com/csharp/singleton.html

ما عليك هو أن تقرر ما هيتر تريد كسول التهيئة أو لا.كسول التهيئة يعني أن الكائن الموجودة داخل المفرد يتم إنشاؤه في أول الدعوة إلى ذلك مثلا :

MySingleton::getInstance()->doWork();

إن هذه الدعوة ليست إلا في وقت لاحق ، هناك خطر من حالة سباق بين المواضيع كما هو موضح في المادة.ومع ذلك ، إذا وضعت

MySingleton::getInstance()->initSingleton();

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

إذا كنت تبحث عن أكثر المحمولة ، و أسهل حل أنك يمكن أن تتحول إلى دفعة.

دفعة::call_once يمكن استخدام الخيط آمنة التهيئة.

دورته بسيطة جدا للاستخدام, و سوف يكون الجزء القادم C++0x القياسية.

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

وبالنظر إلى حقيقة أن اللغة في حد ذاته ليس موضوع الوعي ، بالإضافة إلى تحسين أسلوب الكتابة المحمولة موثوقة c++ المفرد من الصعب جدا (إن لم يكن من المستحيل) ، انظر "C++ و مخاطر مزدوجة-فحص تأمين"سكوت مايرز اندريه Alexandrescu.

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

MSDN الاستشهاد:"المواضيع من عملية واحدة يمكن استخدام كائن مقطع هامة المتبادلة-استبعاد التزامن.".

و http://msdn.microsoft.com/en-us/library/windows/desktop/ms682530(v=مقابل 85).aspx

clearify كذلك:

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

الآن, إذا كان "كسول شيدت" ليس شرطا التالية هو الحل سواء عبر وحدة آمنة مؤشر الترابط-الآمن ، وحتى المحمولة:

struct X { };

X * get_X_Instance()
{
    static X x;
    return &x;
}
extern int X_singleton_helper = (get_X_instance(), 1);

إنه عبر وحدة آمنة لأننا نستخدم محليا-راقب ثابت كائن بدلا من الملف/مساحة راقب كائن العالمية.

إنه مؤشر الترابط-الآمن بسبب:X_singleton_helper يجب تعيين إلى القيمة الصحيحة قبل الدخول الرئيسية أو DllMain ليس كسول شيدت أيضا بسبب هذه الحقيقة) في هذا التعبير الفاصلة المشغل, لا علامات الترقيم.

صراحة استخدام "extern" هنا لمنع مترجم تحسين ذلك(مخاوف حول سكوت مايرز المادة العدو الكبير هو محسن.), و أيضا جعل ساكنة-تحليل أداة مثل pc-الوبر الصمت."قبل الرئيسية/DllMain" هو سكوت ماير يسمى "ترابط واحد جزء بدء التشغيل" في "فعالة C++ 3" البند 4.

ومع ذلك أنا لست متأكدا جدا حول ما إذا كان المترجم يسمح لتحسين الاتصال get_X_instance() وفقا اللغة القياسية ، يرجى التعليق.

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

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