Как я могу создать потокобезопасный шаблон синглтона в Windows?

Дата отображается в GMT: 2012-02-29 00:00:00 +0000 - 2012-03-01 22:00:00 +0200. Также не забудьте изменить время перехода на летнее время, что объясняет, почему вы иногда получаете разницу в 3 часа.

Дата результата верна, но отладчик отображает ее в GMT.

16
задан Community 23 May 2017 в 12:00
поделиться

7 ответов

Если Вы, используют Visual C++ 2005/2008, можно использовать проверенный дважды шаблон блокировки, с тех пор" , энергозависимые переменные ведут себя как заборы ". Это - самый эффективный способ реализовать лениво инициализированный одиночный элемент.

От MSDN Magazine:

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 явно добавляет к семантике энергозависимых для создания этого возможным.

необходимо будет объявить, и инициализируют КРИТИЧЕСКИЙ РАЗДЕЛ в другом месте в коде. Но та инициализация является дешевой, таким образом, ленивая инициализация обычно не важна.

11
ответ дан Eclipse 23 May 2017 в 12:00
поделиться

Можно использовать ОС, примитивную, такую как взаимное исключение или критический раздел для обеспечения ориентированной на многопотоковое исполнение инициализации однако, это подвергнется издержкам каждый раз, когда одноэлементному указателю получают доступ (из-за получения блокировки). Это также не портативно.

1
ответ дан Henk 23 May 2017 в 12:00
поделиться

Существует один проясняющий вопрос, который необходимо рассмотреть для этого вопроса. Вы требуете...

  1. , Что один и только один экземпляр класса когда-либо на самом деле создается
  2. , Много экземпляров класса могут быть созданы, но должен только быть один истинный категорический экземпляр класса

существует много образцов в сети для реализации этих шаблонов в C++. Вот Образец Проекта Кода

1
ответ дан JaredPar 23 May 2017 в 12:00
поделиться

Следующее объясняет, как сделать это в C#, но то же самое понятие относится к любому языку программирования, который поддерживал бы шаблон "одиночка"

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

, Что необходимо решить, хотите ли Вы ленивую инициализацию или нет. Ленивая инициализация означает, что объект, содержавший в одиночном элементе, создается на первом вызове к ней исключая:

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

, если тот вызов не выполняется до позже, существует опасность состояния состязания между потоками, как объяснено в статье. Однако, если бы Вы помещаете

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

в самом начале Вашего кода, где Вы предполагаете, что это было бы ориентировано на многопотоковое исполнение, тогда Вы больше не ленивая инициализация, Вы еще потребуете "немного" вычислительная мощность, когда Ваше приложение запустится. Однако это решит много головных болей об условиях состязания, если Вы сделаете так.

0
ответ дан Eric 23 May 2017 в 12:00
поделиться

Простой способ гарантировать межплатформенная ориентированная на многопотоковое исполнение инициализация одиночного элемента должна выполнить его явно (через вызов к статической функции членства на одиночном элементе) в основном потоке Вашего приложения прежде , Ваше приложение запускает любые другие потоки (или по крайней мере любые другие потоки, которые получат доступ к одиночному элементу).

Удостоверяющийся ориентированный на многопотоковое исполнение доступ к одиночному элементу тогда достигается обычным способом со взаимоисключающими разделами / критическими разделами.

Ленивая инициализация может также быть достигнута с помощью подобного механизма. Обычная проблема, с которой встречаются с этим, состоит в том, что взаимное исключение, необходимое для обеспечения потокобезопасности, часто инициализируется в самом одиночном элементе, который просто продвигает проблему потокобезопасности к инициализации взаимоисключающего раздела / критического раздела. Один способ преодолеть эту проблему состоит в том, чтобы создать и инициализировать взаимоисключающий раздел / критический раздел в основном потоке Вашего приложения тогда передают его одиночному элементу через вызов к статической функции членства. Тяжелая инициализация одиночного элемента может тогда произойти ориентированным на многопотоковое исполнение способом с помощью этого предварительно инициализированного взаимного исключения / критического раздела. Например:

// 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
        }
};

Однако существуют серьезные основания избежать использования одиночных элементов в целом (и почему они иногда упоминаются как антишаблон ):

  • Они - по существу прославленные глобальные переменные
  • , Они могут привести к высокой связи между разрозненными частями приложения
  • , Они могут сделать поблочное тестирование более сложным или невозможным (из-за трудно в свопинге реальных одиночных элементов с поддельными реализациями)

, альтернатива должна использовать 'логический одиночный элемент', посредством чего Вы создаете и инициализируете единственный экземпляр класса в основном потоке и передаете его объектам, которые требуют его. Этот подход может стать громоздким, где существует много объектов, которые Вы хотите создать как одиночные элементы. В этом случае разрозненные объекты могут быть связаны в единственный объект 'Контекста', который тогда роздан в случае необходимости.

13
ответ дан 8 revs 23 May 2017 в 12:00
поделиться

При поиске более портативного, и более легкого решения Вы могли бы обратиться к повышению.

повышение:: call_once может использоваться для ориентированной на многопотоковое исполнение инициализации.

Его довольно простое для использования, и будет часть следующего C++ 0x стандарт.

0
ответ дан mmocny 23 May 2017 в 12:00
поделиться

Существует много способов сделать ориентированную на многопотоковое исполнение Singleton* инициализация на окнах. На самом деле некоторые из них являются даже межплатформенными. В ТАК поток, с которым Вы связались, они искали Singleton, которая лениво создается в C, который немного более конкретен, и может быть немного более хитрым, чтобы сделать правильно, учитывая запутанность модели памяти, под которой Вы работаете.

  • , который Вы никогда не должны использовать
-1
ответ дан 1800 INFORMATION 23 May 2017 в 12:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: