Потоко-бесопасный синглетон
От: SchweinDeBurg Россия http://zarezky.spb.ru/
Дата: 24.05.06 07:25
Оценка:
Доброго времени суток всем нам!

Понадобился мне тут сабж... в boost'е ничего подобного, к моему глубочайшему удивлению, не обнаружилось; гуглевание по словам "C++ singleton thread safe" выдало лишь массу ссылок на "общие слова", по прочтении которых наваялось вот такое:

// interface

template <class _Class_t>
class Singleton
{
// construction/destruction
protected:
    Singleton(void);
    ~Singleton(void);

// copying/assignment - disabled and thus not implemented
private:
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);

// object creator/accessor
public:
    static _Class_t& GetObject(void);

// attributes
private:
    class Locker: public CRITICAL_SECTION
    {
        friend class Singleton<_Class_t>;
        Locker(void);
        ~Locker(void);
        void Enter(void);
        void Leave(void);
    };
    static Locker m_objectLocker;
};

// Singleton<> implementation

template <class _Class_t>
inline Singleton<_Class_t>::Singleton(void)
{
}

template <class _Class_t>
inline Singleton<_Class_t>::~Singleton(void)
{
}

template <class _Class_t>
_Class_t& Singleton<_Class_t>::GetObject(void)
{
    m_objectLocker.Enter();
    static _Class_t* pObject;
    if (pObject == NULL)
    {
        pObject = new _Class_t();
    }
    m_objectLocker.Leave();
    return (*pObject);
}

template <class _Class_t>
typename Singleton<_Class_t>::Locker Singleton<_Class_t>::m_objectLocker;

// Singleton<>::Locker implementation

template <class _Class_t>
inline Singleton<_Class_t>::Locker::Locker(void)
{
    ::InitializeCriticalSection(this);
}

template <class _Class_t>
inline Singleton<_Class_t>::Locker::~Locker(void)
{
    ::DeleteCriticalSection(this);
}

template <class _Class_t>
inline void Singleton<_Class_t>::Locker::Enter(void)
{
    ::EnterCriticalSection(this);
}

template <class _Class_t>
inline void Singleton<_Class_t>::Locker::Leave(void)
{
    ::LeaveCriticalSection(this);
}

Метод использования очевиден:

class MyOneAndOnly: public Singleton<MyOneAndOnly> { ... };

MyOneAndOnly::GetObject().some_method();

Теперь собственно проблемы/вопросы:

  1. Обращение к методам MyOneAndOnly потенциально возможно из конструкторов/деструкторов глобальных объектов (почему pObject и создается в куче). С первыи проблем, как я понимаю не возникнет, так как при первом же общении произойдет вызов new _Class_t. А вот деструкторами все хуже, потому как никаких гарантий, что уже не был разрушен Locker, у меня нет. Это можно как-то преодолеть?

  2. Очевидно, что когда-то нужно вызвать delete pObject — но как это сделать "безопасно" (то есть, с гарантией, что все глобальные объекты уже разрушены)? Копать в сторону atexit()?

  3. Я правильно понимаю, что реализовать singleton для класса, который не имеет конструктора по умолчанию, невозможно?

P.S.
В ожидании ответов пошел читать Паттерн Singleton (Одиночка). Примеры использования
Автор(ы): Дмитрий Федоров
Дата: 14.11.2002
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
- Искренне ваш, Поросенок Пафнутий ~ ICQ#116846877
In Windows, there’s always a catch… © Paul DiLascia
Re: Потоко-бесопасный синглетон
От: DigitalGuru Россия http://svetlyak.ru
Дата: 24.05.06 07:41
Оценка: 1 (1) +1 :))
Здравствуйте, SchweinDeBurg, Вы много чего писали.

Почитать Александреску. Поставить велосипед в сарай. Использовать Loki.
Re[2]: Потоко-бесопасный синглетон
От: SchweinDeBurg Россия http://zarezky.spb.ru/
Дата: 24.05.06 07:58
Оценка: -1
Здравствуйте, DigitalGuru, Вы писали:

DG>Почитать Александреску. Поставить велосипед в сарай. Использовать Loki.


Отпадает — мне для "промышленного" кода надо. Loki, в отличие от boost'а, я таковым не воспринимаю.

P.S.
Сорри за взаимную категоричность.
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
- Искренне ваш, Поросенок Пафнутий ~ ICQ#116846877
In Windows, there’s always a catch… © Paul DiLascia
Re: Потоко-бесопасный синглетон
От: Константин Л. Франция  
Дата: 24.05.06 08:48
Оценка: 14 (1)
Здравствуйте, SchweinDeBurg, Вы писали:

[]

SDB>// attributes

SDB>private:
SDB> class Locker: public CRITICAL_SECTION
SDB> {
SDB> friend class Singleton<_Class_t>;
SDB> //public://???
SDB> Locker(void);
SDB> ~Locker(void);
SDB> void Enter(void);
SDB> void Leave(void);
SDB> };
SDB> static Locker m_objectLocker;
SDB>};

[]

SDB>MyOneAndOnly::GetObject().some_method();

SDB>[/ccode]
SDB>Теперь собственно проблемы/вопросы:

SDB>

    SDB>
  1. Обращение к методам MyOneAndOnly потенциально возможно из конструкторов/деструкторов глобальных объектов (почему pObject и создается в куче). С первыи проблем, как я понимаю не возникнет, так как при первом же общении произойдет вызов new _Class_t. А вот деструкторами все хуже, потому как никаких гарантий, что уже не был разрушен Locker, у меня нет. Это можно как-то преодолеть?

    SDB>
  2. Очевидно, что когда-то нужно вызвать delete pObject — но как это сделать "безопасно" (то есть, с гарантией, что все глобальные объекты уже разрушены)? Копать в сторону atexit()?

    SDB>
  3. Я правильно понимаю, что реализовать singleton для класса, который не имеет конструктора по умолчанию, невозможно?
    SDB>

SDB>P.S.

SDB>В ожидании ответов пошел читать Паттерн Singleton (Одиночка). Примеры использования
Автор(ы): Дмитрий Федоров
Дата: 14.11.2002


Почему Loki не воспринимаешь?

1) Зачем писать свой Locker, когда есть ATL::CComAutoCriticalSection, ATL::CComCritSecLock? Или нет возможности их юзать?
2) Зачем у Locker'а private конструктор? Класс же и так private? Из-за этого тебе пришлось тянуть friend. Сделай конструктор/десруктор public
3) Есть идея создавать CS в куче и вообще не удалять ни твой объект, ни CS. При грохе процесса все почистится. Но это зависит от "сложности" деструктора MyOneAndOnly
4) Может все-таки Loki + напильник?
Re[2]: Потоко-бесопасный синглетон
От: SchweinDeBurg Россия http://zarezky.spb.ru/
Дата: 24.05.06 09:22
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>Почему Loki не воспринимаешь?


Сложно сказать... для меня это больше "академический эксперимент" по проверке и демонстрации возможностей C++ и каких-то концепций, чем "боевой" продукт.

КЛ>1) Зачем писать свой Locker, когда есть ATL::CComAutoCriticalSection, ATL::CComCritSecLock? Или нет возможности их юзать?


Нет, нужна максимальная независимость от любых библиотек (исключая STL).

КЛ>2) Зачем у Locker'а private конструктор? Класс же и так private? Из-за этого тебе пришлось тянуть friend. Сделай конструктор/десруктор public


Согласен.

КЛ>3) Есть идея создавать CS в куче и вообще не удалять ни твой объект, ни CS. При грохе процесса все почистится.


За такой подход у нас на работе рихтуют напильником... сначала руки, потом — голову. И очень правильно ИМХО делают.

КЛ>Но это зависит от "сложности" деструктора MyOneAndOnly


Вот именно.

КЛ>4) Может все-таки Loki + напильник?


Нет уж, увольте. Я тут нагугли-таки пару полезных ссылочек по теме со вполне читабельным кодом:

Singleton.h

Context Singletons &mdash; context-specific shared objects in C++

Как я и предполагал, через atexit() проблема решается.
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
- Искренне ваш, Поросенок Пафнутий ~ ICQ#116846877
In Windows, there’s always a catch… © Paul DiLascia
Re[3]: Потоко-бесопасный синглетон
От: DigitalGuru Россия http://svetlyak.ru
Дата: 24.05.06 09:30
Оценка: +1
Здравствуйте, SchweinDeBurg, Вы писали:

SDB>Как я и предполагал, через atexit() проблема решается.


Конечно! У Александреску именно так и написано
Re[4]: Потоко-бесопасный синглетон
От: SchweinDeBurg Россия http://zarezky.spb.ru/
Дата: 24.05.06 09:34
Оценка:
Здравствуйте, DigitalGuru, Вы писали:

DG>Конечно! У Александреску именно так и написано


"Great minds think alike..." Но код из Context Singletons — context-specific shared objects in C++ читается значительно приятнее.
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
- Искренне ваш, Поросенок Пафнутий ~ ICQ#116846877
In Windows, there’s always a catch… © Paul DiLascia
Re[3]: Потоко-бесопасный синглетон
От: Константин Л. Франция  
Дата: 24.05.06 09:45
Оценка:
Здравствуйте, SchweinDeBurg, Вы писали:

SDB>Здравствуйте, Константин Л., Вы писали:


КЛ>>Почему Loki не воспринимаешь?


SDB>Сложно сказать... для меня это больше "академический эксперимент" по проверке и демонстрации возможностей C++ и каких-то концепций, чем "боевой" продукт.


КЛ>>1) Зачем писать свой Locker, когда есть ATL::CComAutoCriticalSection, ATL::CComCritSecLock? Или нет возможности их юзать?


SDB>Нет, нужна максимальная независимость от любых библиотек (исключая STL).


КЛ>>2) Зачем у Locker'а private конструктор? Класс же и так private? Из-за этого тебе пришлось тянуть friend. Сделай конструктор/десруктор public


SDB>Согласен.


КЛ>>3) Есть идея создавать CS в куче и вообще не удалять ни твой объект, ни CS. При грохе процесса все почистится.


SDB>За такой подход у нас на работе рихтуют напильником... сначала руки, потом — голову. И очень правильно ИМХО делают.


ИМХО тоже, просто предложил как один из "возможных" вариантов

КЛ>>Но это зависит от "сложности" деструктора MyOneAndOnly


SDB>Вот именно.


КЛ>>4) Может все-таки Loki + напильник?


SDB>Нет уж, увольте. Я тут нагугли-таки пару полезных ссылочек по теме со вполне читабельным кодом:


SDB>Singleton.h


Есть сомнения по поводу необходимости наследования от SingletonBase. Этот класс является аналогом boost::noncopyable и ничего не дает кроме невозможности копирования.

Так что необходимость наследования от него считаю лишней

SDB>Context Singletons &mdash; context-specific shared objects in C++


SDB>Как я и предполагал, через atexit() проблема решается.
Re: Потоко-бесопасный синглетон
От: Ivan Россия www.rsdn.ru
Дата: 24.05.06 09:47
Оценка: 14 (1)
Здравствуйте, SchweinDeBurg, Вы писали:

SDB>Понадобился мне тут сабж... в boost'е ничего подобного, к моему глубочайшему удивлению, не обнаружилось;


в boost'е есть синглтон — но в виде детали реализации библиотеки pool — boost\pool\detail\singleton.hpp
идея потокобезопасности проста и эффективна — используется синглтон Майерса + instance() первый раз вызывается в конструкторе глобальной переменной, это происходит до входа в main и, следовательно, потокобезопасно.

код примерно такой
template<class T> class singleton : public T
{
private:
...
   struct creator
   {
       creator()
       {
          singleton<T>::instance();
       }  
   }
   static creator s_singleton_creator;

public:
   static T& instance()
   {
      static T inst;
      return inst;
   }
};

template<class T> typename singleton<T>::creator singleton<T>::s_singleton_creator;
Re[4]: Потоко-бесопасный синглетон
От: SchweinDeBurg Россия http://zarezky.spb.ru/
Дата: 24.05.06 09:49
Оценка: 1 (1)
Здравствуйте, Константин Л., Вы писали:

КЛ>ИМХО тоже, просто предложил как один из "возможных" вариантов


Для меня он не возможен, даже в кавычках.

КЛ>Есть сомнения по поводу необходимости наследования от SingletonBase. Этот класс является аналогом boost::noncopyable и ничего не дает кроме невозможности копирования.


Угу.

КЛ>Так что необходимость наследования от него считаю лишней


Ну, это уже частности... при наличии рашпиля.
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
- Искренне ваш, Поросенок Пафнутий ~ ICQ#116846877
In Windows, there’s always a catch… © Paul DiLascia
Re[2]: Потоко-бесопасный синглетон
От: SchweinDeBurg Россия http://zarezky.spb.ru/
Дата: 24.05.06 10:03
Оценка:
Здравствуйте, Ivan, Вы писали:

I>в boost'е есть синглтон — но в виде детали реализации библиотеки pool — boost\pool\detail\singleton.hpp

I>идея потокобезопасности проста и эффективна — используется синглтон Майерса + instance() первый раз вызывается в конструкторе глобальной переменной, это происходит до входа в main и, следовательно, потокобезопасно.

Засмотрел. Все бы хорошо, но:

1.

// The following helper classes are placeholders for a generic "singleton"
// class. The classes below support usage of singletons, including use in
// program startup/shutdown code, AS LONG AS there is only one thread
// running before main() begins, and only one thread running after main()
// exits
.


Будучи параноиком, выделенным смущен.

2.

// Furthermore, since the instance() function contains the object, instead
// of the singleton_default class containing a static instance of the
// object, that object is guaranteed to be constructed (at the latest) in
// the first call to instance(). This permits calls to instance() from
// static code, even if that code is called before the file-scope objects
// in this file have been initialized.


Увы, но разрушение такого синглетона после всех глобальных объектов, которые им пользовались, не гарантируется.

Так что буду сейчас точить под себя Феникса, описанного в Context Singletons — context-specific shared objects in C++. Но за инфу все равно спасибо.
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
- Искренне ваш, Поросенок Пафнутий ~ ICQ#116846877
In Windows, there’s always a catch… © Paul DiLascia
Re: Потоко-бесопасный синглетон
От: Conr Россия  
Дата: 24.05.06 10:06
Оценка: 14 (1)
Здравствуйте, SchweinDeBurg, Вы писали:

SDB>Доброго времени суток всем нам!


SDB>Понадобился мне тут сабж... в boost'е ничего подобного, к моему глубочайшему удивлению, не обнаружилось; гуглевание по словам "C++ singleton thread safe" выдало лишь массу ссылок на "общие слова", по прочтении которых наваялось вот такое:

Так на RSDN же и была интересная тема thread safe singlton &mdash; возможно ли такое в принципе
Автор: Andrew S
Дата: 06.02.04


хъ
Re: Потоко-бесопасный синглетон
От: Андрей Коростелев Голландия http://www.korostelev.net/
Дата: 24.05.06 10:10
Оценка: 14 (1)
Здравствуйте, SchweinDeBurg, Вы писали:

SDB>Доброго времени суток всем нам!


SDB>Понадобился мне тут сабж... в boost'е ничего подобного, к моему глубочайшему удивлению, не обнаружилось; гуглевание по словам "C++ singleton thread safe" выдало лишь массу ссылок на "общие слова", по прочтении которых наваялось вот такое:


Кроме всего прочего, советую почитать эту
Автор: LuciferMoscow
Дата: 21.10.05
ветку
-- Андрей
Re[2]: Потоко-бесопасный синглетон
От: SchweinDeBurg Россия http://zarezky.spb.ru/
Дата: 24.05.06 10:13
Оценка:
Здравствуйте, Conr, Вы писали:

C>Так на RSDN же и была интересная тема thread safe singlton &mdash; возможно ли такое в принципе
Автор: Andrew S
Дата: 06.02.04


Ну, вот так всегда: спросишь что-нибудь на RSDN — пошлют в Гугль, а если первым делом скажешь, что в Гугле уже был — "а чего ты на RSDN не посмотрел?.."

Спасибо, Вит, занес ссылку в избранное, почитаю на досуге.
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
- Искренне ваш, Поросенок Пафнутий ~ ICQ#116846877
In Windows, there’s always a catch… © Paul DiLascia
Re[5]: Потоко-бесопасный синглетон
От: Аноним  
Дата: 24.05.06 10:29
Оценка:
Здравствуйте, SchweinDeBurg, Вы писали:

SDB>Здравствуйте, DigitalGuru, Вы писали:


DG>>Конечно! У Александреску именно так и написано


SDB>"Great minds think alike..." Но код из Context Singletons — context-specific shared objects in C++ читается значительно приятнее.


Full disclosure: phoenix is based partly on MC++D's code. In particular, i've stolen Andrei's trick of matching atexit(), manual dtor invokation and the placement new operator .


Еще позабавило имя переменной "myers" .

А что касается реализации Singlton'а, то, мне лично, приятнее вот это:

class my_singleton_t {
...
};

extern my_singleton_t my_singleton;
Re[3]: Потоко-бесопасный синглетон
От: Аноним  
Дата: 24.05.06 10:36
Оценка:
Здравствуйте, SchweinDeBurg, Вы писали:

SDB>Здравствуйте, Ivan, Вы писали:


[snip]

SDB>1.

SDB>

SDB>// The following helper classes are placeholders for a generic "singleton"
SDB>// class. The classes below support usage of singletons, including use in
SDB>// program startup/shutdown code, AS LONG AS there is only one thread
SDB>// running before main() begins, and only one thread running after main()
SDB>// exits
.


SDB>Будучи параноиком, выделенным смущен.


А у вас часто создаются нити до входа в main? Правда, очень интересно где это может понадобиться.

[snip]

SDB>Увы, но разрушение такого синглетона после всех глобальных объектов, которые им пользовались, не гарантируется.


здесь
Автор: Erop
Дата: 20.04.06
интересное, ИМХО, мнение по этому поводу.

[snip]
Re[4]: Потоко-бесопасный синглетон
От: SchweinDeBurg Россия http://zarezky.spb.ru/
Дата: 24.05.06 10:48
Оценка:
Здравствуйте, <Аноним>, Вы писали:

SDB>>Будучи параноиком, выделенным смущен.

А>А у вас часто создаются нити до входа в main? Правда, очень интересно где это может понадобиться.

См. выделенное. Мне крайне не хочется копаться в исходниках CRT очередного компилятора, чтобы убедиться, что до входа в main() мы имеем ровно один поток.

А>здесь
Автор: Erop
Дата: 20.04.06
интересное, ИМХО, мнение по этому поводу.


ОК, засмотрю.
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
- Искренне ваш, Поросенок Пафнутий ~ ICQ#116846877
In Windows, there’s always a catch… © Paul DiLascia
Re[3]: Потоко-бесопасный синглетон
От: Ivan Россия www.rsdn.ru
Дата: 24.05.06 11:23
Оценка:
Здравствуйте, SchweinDeBurg, Вы писали:

SDB>Засмотрел. Все бы хорошо, но:


SDB>1.

SDB>

SDB>// AS LONG AS there is only one thread
SDB>// running before main() begins, and only one thread running after main()
SDB>// exits
.


если речь идет о Dll модуле, то вызов DllMain происходит внутри спецальной секции LoaderLock и создание других потоков в этот момент будет приостановлено до завершения работы DllMain. В exe модуле технически завести несколько потоков можно — в конструктторах глобальных переменных, но я с таким не встречался.
если представить, что кто-то создает потоки в конструкторах глобальных переменных, то в это время еще не завершилась инициализация CRT в главном потоке — это может создать проблемы при инициализации CRT в порожденных потоках. и второй момент — при обращении из этих потоков к глобальным переменным — можно получить доступ к переменным, которые еще не успели сконструироваться в главном потоке.

SDB>Увы, но разрушение такого синглетона после всех глобальных объектов, которые им пользовались, не гарантируется.

да, здесь похоже по стандарту UB при обращении после его разрушения, на практике для Visual C++ — он 'возродится'
Re[3]: Потоко-бесопасный синглетон
От: Conr Россия  
Дата: 24.05.06 12:25
Оценка: :)
Здравствуйте, SchweinDeBurg, Вы писали:

SDB>Ну, вот так всегда: спросишь что-нибудь на RSDN — пошлют в Гугль, а если первым делом скажешь, что в Гугле уже был — "а чего ты на RSDN не посмотрел?.."

Хочешь я тебе тулзу дам, которая ищет одновременно и там, и там, объединяя результаты вместе? Только я её пока в гугль-группах и на codeproject искать не научил, но это в планах есть...

SDB>Спасибо, Вит, занес ссылку в избранное, почитаю на досуге.
Re: Потоко-бесопасный синглетон
От: Programmierer AG  
Дата: 24.05.06 13:40
Оценка: 15 (2)
Здравствуйте, SchweinDeBurg, Вы писали:

Смущает пара моментов, вроде в ветке не упоминались:
SDB>
SDB>    static Locker m_objectLocker; // 1) инициализируется в runtime - обращение
                                      // к GetObject из других единиц трансляции
                                      //  может обломиться

SDB>template <class _Class_t>
SDB>_Class_t& Singleton<_Class_t>::GetObject(void)
SDB>{
SDB>    m_objectLocker.Enter();
SDB>    static _Class_t* pObject;
SDB>    if (pObject == NULL)
SDB>    {
SDB>        pObject = new _Class_t();// 2) маловероятно, но может бросить исключение,
SDB>    }
SDB>    m_objectLocker.Leave(); // ...и сюда мы не попадаем
SDB>    return (*pObject);
SDB>}

SDB>

SDB>Теперь собственно проблемы/вопросы:

SDB>[list=1]

SDB>
  • Обращение к методам MyOneAndOnly потенциально возможно из конструкторов/деструкторов глобальных объектов (почему pObject и создается в куче). С первыи проблем, как я понимаю не возникнет,
    См. 1), могут возникнуть.
  • Re[4]: Потоко-бесопасный синглетон
    От: Ivan Россия www.rsdn.ru
    Дата: 24.05.06 13:49
    Оценка:
    Здравствуйте, Ivan, Вы писали:

    I>да, здесь похоже по стандарту UB при обращении после его разрушения, на практике для Visual C++ — он 'возродится'

    насчет 'возродится' я погорячился , после вызова деструктора новый экземпляр не будет создан и в visual c++ (проверил на 2005)
    Re[2]: Потоко-бесопасный синглетон
    От: SchweinDeBurg Россия http://zarezky.spb.ru/
    Дата: 24.05.06 14:00
    Оценка:
    Здравствуйте, Programmierer AG, Вы писали:

    PA>Смущает пара моментов, вроде в ветке не упоминались:

    SDB>>
    SDB>>    static Locker m_objectLocker; // 1) инициализируется в runtime - обращение
    PA>                                      // к GetObject из других единиц трансляции
    PA>                                      //  может обломиться
    SDB>>        pObject = new _Class_t();// 2) маловероятно, но может бросить исключение,
    SDB>>    m_objectLocker.Leave(); // ...и сюда мы не попадаем
    SDB>>


    PA>См. 1), могут возникнуть.


    М-дя... 2)-е легко объехать как-то а-ля

    try
    {
    ...
    }
    catch (...)
    {
        m_objectLocker.Leave();
        throw;
    }

    А вот с 1)-м и правда засада... хотя можно, конечно, "высокоприоритетной" #pragma init_seg() воспользоваться.
    [ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
    - Искренне ваш, Поросенок Пафнутий ~ ICQ#116846877
    In Windows, there’s always a catch… © Paul DiLascia
    Re[4]: Потоко-бесопасный синглетон
    От: SchweinDeBurg Россия http://zarezky.spb.ru/
    Дата: 24.05.06 14:01
    Оценка:
    Здравствуйте, Conr, Вы писали:

    C>Хочешь я тебе тулзу дам, которая ищет одновременно и там, и там, объединяя результаты вместе? Только я её пока в гугль-группах и на codeproject искать не научил, но это в планах есть...


    Ну, вот как допишешь...
    [ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
    - Искренне ваш, Поросенок Пафнутий ~ ICQ#116846877
    In Windows, there’s always a catch… © Paul DiLascia
    Re[3]: Потоко-бесопасный синглетон
    От: Programmierer AG  
    Дата: 24.05.06 14:22
    Оценка:
    Здравствуйте, SchweinDeBurg, Вы писали:

    SDB>М-дя... 2)-е легко объехать как-то а-ля

    Или по старинке, через RTTI.
    SDB>А вот с 1)-м и правда засада... хотя можно, конечно, "высокоприоритетной" #pragma init_seg() воспользоваться.
    Или сделать инициализацию на Schwarz counter'ах. Хотя если допустить, что конструкторы глобальных объектов могут создавать потоки, безопасная и прозрачная инициализация синглтона+его мьютекса у меня в голове не укладывается.
    Re[5]: Потоко-бесопасный синглетон
    От: Ivan Россия www.rsdn.ru
    Дата: 24.05.06 14:40
    Оценка: 40 (4)
    Здравствуйте, Ivan, Вы писали:

    I>Здравствуйте, Ivan, Вы писали:


    еще один не вполне "законный" и непереносимый вариант обойти проблему порядка создания/разрушения — использовать CRTALLOC/init_seg — чтобы синглтон гарантированно создавался до первого конструктора глобального объекта и следовательно разрушался после вызова деструктора последнего такого объекта

    template<class T> class singleton : public T
    {
    private:
        static int creator()
        {
            singleton<T>::instance();
            return 0;
        }
    
        static int (__cdecl *pcreator)();
    
    public:
        static T& instance()
        {
            static int use_pcreate = pcreator(); //
    
            static singleton<T> inst;
            return inst;
        }
    };
    
    #pragma data_seg(".CRT$XIC")
    template<class T> __declspec(allocate(".CRT$XIC")) int (__cdecl *singleton<T>::pcreator)() = singleton<T>::creator;
    #pragma data_seg()
    Re[6]: Потоко-бесопасный синглетон
    От: SchweinDeBurg Россия http://zarezky.spb.ru/
    Дата: 24.05.06 14:47
    Оценка:
    Здравствуйте, Ivan, Вы писали:

    I>еще один не вполне "законный" и непереносимый вариант обойти проблему порядка создания/разрушения — использовать CRTALLOC/init_seg — чтобы синглтон гарантированно создавался до первого конструктора глобального объекта и следовательно разрушался после вызова деструктора последнего такого объекта


    О, вот за эту идею спасибо! Непереносимость меня не заботит совершенно, а вот законность-то тут чем нарушается?
    [ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
    - Искренне ваш, Поросенок Пафнутий ~ ICQ#116846877
    In Windows, there’s always a catch… © Paul DiLascia
    [FYI] Еще ссылка по теме
    От: SchweinDeBurg Россия http://zarezky.spb.ru/
    Дата: 24.05.06 15:05
    Оценка:
    Singleton.h

    P.S.
    А казалось бы, какая тривиальная вещь — объект, существующий в единственном экземпляре...
    [ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
    - Искренне ваш, Поросенок Пафнутий ~ ICQ#116846877
    In Windows, there’s always a catch… © Paul DiLascia
    Re[7]: Потоко-бесопасный синглетон
    От: Ivan Россия www.rsdn.ru
    Дата: 24.05.06 15:07
    Оценка:
    Здравствуйте, SchweinDeBurg, Вы писали:

    SDB>О, вот за эту идею спасибо! Непереносимость меня не заботит совершенно, а вот законность-то тут чем нарушается?


    под незаконностью я имел в виду недокументированность идентификаторов CRT, с помощью которых можно управлять порядком. $XI — это C инициализаторы, $XC — c++,
    но в будущих версиях CRT это могут изменить

    и потенциальная проблема здесь — два таких синглтона будут создаваться/разрушаться уже в проивзольном порядке относительно друг друга — хотя этим уже можно управлять (в том числе и подкручивая идентификатор секции)
    Re[8]: Потоко-бесопасный синглетон
    От: SchweinDeBurg Россия http://zarezky.spb.ru/
    Дата: 24.05.06 15:22
    Оценка:
    Здравствуйте, Ivan, Вы писали:

    I>но в будущих версиях CRT это могут изменить


    Что-то я сомневаюсь. Такие вещи МС обычно блюдет, насколько я знаю.

    I>и потенциальная проблема здесь — два таких синглтона будут создаваться/разрушаться уже в проивзольном порядке относительно друг друга


    Да, это первое, что пришло мне в голову.

    I> — хотя этим уже можно управлять (в том числе и подкручивая идентификатор секции)


    Угу. В любом случае — вариант очень интересный, а главное железный. Я вот сейчас еще ZThread смотрю, что там Eric Crahen накрутил.
    [ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
    - Искренне ваш, Поросенок Пафнутий ~ ICQ#116846877
    In Windows, there’s always a catch… © Paul DiLascia
    Re[3]: Потоко-бесопасный синглетон
    От: LeeMouse Россия  
    Дата: 24.05.06 17:13
    Оценка:
    Здравствуйте, SchweinDeBurg, Вы писали:

    SDB>Отпадает — мне для "промышленного" кода надо. Loki, в отличие от boost'а, я таковым не воспринимаю.


    Это не есть проблема Loki... Сами догадаетесь чья?
    Re: Потоко-бесопасный синглетон
    От: Аноним  
    Дата: 24.05.06 17:29
    Оценка:
    Здравствуйте, SchweinDeBurg, Вы писали:

    Рекомендую, хорошая книжка
    Design Patterns Explained: A New Perspective on Object-Oriented Design
    By Alan Shalloway, James R. Trott

    ftp://files.zipsites.ru/books/edocs/Addison_Wesley/Design.Patterns.Explained.A.New.Perspective.on.Object.Oriented.Design.2nd.Edition..chm

    Размер 1,6 Мб


    Выдержка оттуда:

    Example 16-4 C++ Code Fragment: Double-Checked Locking Pattern
    class USTax : public CalcTax {
      public:
        static USTax* getInstance();
      private:
        USTax();
        static USTax* instance;
    };
    USTax* USTax::instance= 0;
    
    USTax* USTax::getInstance () {
      if (instance== 0) {
        // do sync here
        if (instance== 0) {
            instance= new USTax;
        }
      }
      return instance;
    }
    Re: Потоко-бесопасный синглетон
    От: WolfHound  
    Дата: 24.05.06 17:53
    Оценка: 18 (2) +1
    Здравствуйте, SchweinDeBurg, Вы писали:

    Почитал я тут... во истину кривая архитектура порождает кривые решения.
    Сам я на синглетоны забил и не жалею.
    Короче читать отсюда
    Автор: WolfHound
    Дата: 16.05.06
    и дальше.
    Для С++ понадобится велосипед типа такого: (полить смартпоинтерами с прочей магией по вкусу)
    template<class T>
    struct InterfaceIID;
    
    struct IServiceProvider
    {
        template<class T>
        T* GetService()
        {
            return reinterpret_cast<T*>(GetServiceByIID(InterfaceIID<T>::IID()));
        }
    protected:
        virtual void* GetServiceByIID(GUID const& giud) = 0;
        virtual ~IServiceProvider(){}
    };
    
    template<>
    struct InterfaceIID<IServiceProvider>
    {
        static GUID const& IID()
        {
            // {0AFA964C-DD0F-43d2-846B-99A3022197A2}
            static const GUID guid = { 0xafa964c, 0xdd0f, 0x43d2, { 0x84, 0x6b, 0x99, 0xa3, 0x2, 0x21, 0x97, 0xa2 } };
            return guid;
        }
    };

    Для остальных интерфейсов делаются аналогичные специализации InterfaceIID.
    При реализации GetServiceByIID можно использовать любые стратегии создания/разрушения сервисов.
    Все остальное один в один как в примере на C#.
    ... << RSDN@Home 1.1.4 beta 6a rev. 436>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[2]: Потоко-бесопасный синглетон
    От: Ivan Россия www.rsdn.ru
    Дата: 24.05.06 19:28
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    WH>Короче читать отсюда
    Автор: WolfHound
    Дата: 16.05.06
    и дальше.

    WH>Для остальных интерфейсов делаются аналогичные специализации InterfaceIID.
    WH>При реализации GetServiceByIID можно использовать любые стратегии создания/разрушения сервисов.
    WH>Все остальное один в один как в примере на C#.

    имхо, этот подход не заменяет синглтон по двум причинам:
    — доступ к "главному" провайдеру IServicepProvider, этот Service Provider напрашивается быть реализованным с помощью шаблона синглтон
    — сложность. для простых приложений это может стать overkill'ом. допустим для небольшого консольного приложения нужна конфигурация и простая подсистема логирования. для них можно применить синглтон.

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

    >Почитал я тут... во истину кривая архитектура порождает кривые решения.

    поэтому на мой взгляд, синглтон и сервисы/конексты дополняют друг друга и использования одного и/или другого никак не свидетельсвует о хорошей или плохой архитектуре.
    Re[3]: Потоко-бесопасный синглетон
    От: WolfHound  
    Дата: 24.05.06 19:52
    Оценка:
    Здравствуйте, Ivan, Вы писали:

    I>имхо, этот подход не заменяет синглтон по двум причинам:

    I>- доступ к "главному" провайдеру IServicepProvider, этот Service Provider напрашивается быть реализованным с помощью шаблона синглтон
    Я ни разу его синглетоном не делал. Конечно он всегда один но глабольной точки доступа к нему нет.
    I>- сложность. для простых приложений это может стать overkill'ом. допустим для небольшого консольного приложения нужна конфигурация и простая подсистема логирования. для них можно применить синглтон.
    Моя практика показывает что такое прокатывает только оочень простых программках.
    А конфиг + логгер (если вспомнить начало топика то и многопоточность) это уже не очень простое приложение.

    I>можно зайти и с другой стороны.

    I>допустим для приложения реализована подсистема логирования в виде синглтона. с течением времени требования к системе логирования увеличиваются, появляется необходимость в управлении логированием в зависимости от контекста и т.п. в этом случае синглтон Logger становится уже IServiceProvider'ом и перенаправляет клиентов в зависимости от контекста в нужную реализацию. при правильной начальной реализации для клиентов этот переход может быть прозрачным.
    Продемонстрируй.

    >>Почитал я тут... во истину кривая архитектура порождает кривые решения.

    I>поэтому на мой взгляд, синглтон и сервисы/конексты дополняют друг друга и использования одного и/или другого никак не свидетельсвует о хорошей или плохой архитектуре.
    Всетки в случае с большими приложениями дерево контекстов само формирует каркас ситемы разделяя ее на четкие слои, а без четкой структуры приложения что-то большее чем "Hello world!" написать проблематично.
    Синглитоны таким свойством не обладают.
    К тому же контексты гораздо слабее связывают систему что есть благо.
    ... << RSDN@Home 1.1.4 beta 6a rev. 436>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re: Потоко-бесопасный синглетон
    От: apm Россия  
    Дата: 24.05.06 21:02
    Оценка: 14 (1)
    Здравствуйте, SchweinDeBurg, Вы писали:

    [..]

    здесь
    BB for fun
    В продолжние темы
    От: SchweinDeBurg Россия http://zarezky.spb.ru/
    Дата: 25.05.06 08:38
    Оценка:
    Рассматривая исходники ZThread, обнаружил следующее:

    template <class T, class InstantiationPolicy, class LockType>
    T* Singleton<T, InstantiationPolicy, LockType>::instance() {
    
        // Uses local static storage to avoid static construction
        // sequence issues. (regaring when the lock is created)
        static T* ptr = 0;    
        static LockType lock;
    
        if(!ptr) {
    
          Guard<LockType, LockedScope> g(lock);
          if(!ptr)        
            InstantiationPolicy::create(ptr);
    
        }
        return const_cast<T*>(ptr);
        
      }
    };

    Поджирненный комментарий поверг меня в некоторое недоумение... откуда у автора такая уверенность?
    [ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
    - Искренне ваш, Поросенок Пафнутий ~ ICQ#116846877
    In Windows, there’s always a catch… © Paul DiLascia
    Re: В продолжние темы
    От: Sergey Россия  
    Дата: 25.05.06 09:12
    Оценка:
    > Поджирненный комментарий поверг меня в некоторое недоумение... откуда у автора такая уверенность?

    Может, у него просто такой компилятор? А VC он в жизни не видал?
    Posted via RSDN NNTP Server 2.0
    Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
    Re[4]: Потоко-бесопасный синглетон
    От: Ivan Россия www.rsdn.ru
    Дата: 25.05.06 09:55
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    I>>можно зайти и с другой стороны.

    I>>допустим для приложения реализована подсистема логирования в виде синглтона. с течением времени требования к системе логирования увеличиваются, появляется необходимость в управлении логированием в зависимости от контекста и т.п. в этом случае синглтон Logger становится уже IServiceProvider'ом и перенаправляет клиентов в зависимости от контекста в нужную реализацию. при правильной начальной реализации для клиентов этот переход может быть прозрачным.
    WH>Продемонстрируй.

    Продемонстрирую на примере COM. созданием экзмепляров управляет фабрика классов — будет компонент синглтоном или нет — зависит от ее реализации и никак не влияет ни на клиентов, ни на реализацию самого компонента. Контекстами и дополнительными сервисами в зависимости от контекста занимается отдельная подсистема, построенная на основе концепции Proxy. клиент получает вместо указателя на компонент — Proxy, которая в зависимости от контекста и его свойств добавляет нужную функциональность. снова это не влияет ни на реализацию клиента, ни на реализацию компонента и никак не связано с фабрикой классов этого компонента.
    хороший пример синглтона/провайдера сервисов — GIT (Global Interface Table), у клиентов есть глобальная точка доступа к GIT, т.к. она стнглтон, в самой GIT могут храниться указатели на различные компоненты — это уже провайдер определенных сервисов.

    повторяя этот дизайн и идеи — т.е. используя шаблоны проектирования "фабрика" и "прокси", можно реализовать Logger так, что новая функциональность будет добавляться прозрачно для клиентов. при этом является ли Logger синглтоном или учитывает ли контекст клиента станет деталью реализации подсистемы логирования.
    Re[5]: Потоко-бесопасный синглетон
    От: WolfHound  
    Дата: 25.05.06 10:24
    Оценка:
    Здравствуйте, Ivan, Вы писали:

    I>повторяя этот дизайн и идеи — т.е. используя шаблоны проектирования "фабрика" и "прокси", можно реализовать Logger так, что новая функциональность будет добавляться прозрачно для клиентов. при этом является ли Logger синглтоном или учитывает ли контекст клиента станет деталью реализации подсистемы логирования.

    С СОМом я работал очень давно и глубоко не лазил.
    Пожалуйста накидай несколько строк псевдокода чтобы понятно было кто на ком стоит.
    ... << RSDN@Home 1.1.4 beta 6a rev. 436>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re: В продолжние темы
    От: bkat  
    Дата: 25.05.06 10:58
    Оценка: 14 (1)
    Ну это "Double-Checked Locking" со всеми последствиями...
    Не уверен, мелькала ли в этом топике ссылка:
    http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
    Re: Потоко-бесопасный синглетон
    От: Bachata Россия  
    Дата: 04.10.06 12:09
    Оценка: 14 (1)
    Здравствуйте, SchweinDeBurg, Вы писали:

    SDB>Я правильно понимаю, что реализовать singleton для класса, который не имеет конструктора по умолчанию, невозможно?


    Можно воспльзоваться библиотекой lib-global.
    Она реализует те же задачи, что и паттерн Singleton, но плюс к этому позволяет работать
    с классами, у которых нет конструктора по умолчанию.
    Re: В продолжние темы
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 04.10.06 15:48
    Оценка:
    SDB>Рассматривая исходники ZThread, обнаружил следующее:

    SDB>
    SDB>template <class T, class InstantiationPolicy, class LockType>
    SDB>T* Singleton<T, InstantiationPolicy, LockType>::instance() {
    
    SDB>    // Uses local static storage to avoid static construction
    SDB>    // sequence issues. (regaring when the lock is created)
    SDB>    static T* ptr = 0;    
    SDB>    static LockType lock;
    
    SDB>    if(!ptr) {
    
    SDB>      Guard<LockType, LockedScope> g(lock);
    SDB>      if(!ptr)        
    SDB>        InstantiationPolicy::create(ptr);
    
    SDB>    }
    SDB>    return const_cast<T*>(ptr);
        
    SDB>  }
    SDB>};
    SDB>

    SDB>Поджирненный комментарий поверг меня в некоторое недоумение... откуда у автора такая уверенность?

    Я полагаю, имеется в виду, что согласно стандарту, инициализация локальных статических объектов (не POD) производится до выполнения первой инструкции функции. Насколько я помню, про POD там оговорено отдельно.
    Т.о., несмотря на уверенный комментарий, static LockType lock возвращает нас все к той же проблеме — нельзя использовать в качестве локера не POD типы. Видимо, автор не в курсе проблематики.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re: Потоко-бесопасный синглетон
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 04.10.06 16:04
    Оценка:
    SDB>
    SDB>private:
    SDB>    class Locker: public CRITICAL_SECTION
    SDB>    {
    SDB>        friend class Singleton<_Class_t>;
    SDB>        Locker(void);
    SDB>        ~Locker(void);
    SDB>        void Enter(void);
    SDB>        void Leave(void);
    SDB>    };
    SDB>    static Locker m_objectLocker;
    SDB>};
    SDB>// Singleton<>::Locker implementation
    
    SDB>template <class _Class_t>
    SDB>inline Singleton<_Class_t>::Locker::Locker(void)
    SDB>{
    SDB>    ::InitializeCriticalSection(this);
    SDB>}
    
    SDB>template <class _Class_t>
    SDB>inline Singleton<_Class_t>::Locker::~Locker(void)
    SDB>{
    SDB>    ::DeleteCriticalSection(this);
    SDB>}
    SDB>



    SDB>
  • Обращение к методам MyOneAndOnly потенциально возможно из конструкторов/деструкторов глобальных объектов (почему pObject и создается в куче). С первыи проблем, как я понимаю не возникнет, так как при первом же общении произойдет вызов new _Class_t. А вот деструкторами все хуже, потому как никаких гарантий, что уже не был разрушен Locker, у меня нет. Это можно как-то преодолеть?

    Для синглтона Мейерса это не является проблемой. А вот с выделенным мной фрагментом кода возникает _очень_ много проблем, связанных с неопределенным порядком инициализации. По сути, нам нужен МТ синглтон в МТ синглтоне — локер ведь тоже обязан быть синглтоном. Решение уже приводили — http://www.rsdn.ru/Forum?mid=531518
    Автор: WolfHound
    Дата: 06.02.04

    Т.е., фактически, все упирается в использовании POD типов в качестве объектов блокировки — так называемый LW мьютекс.

    SDB>
  • Очевидно, что когда-то нужно вызвать delete pObject — но как это сделать "безопасно" (то есть, с гарантией, что все глобальные объекты уже разрушены)? Копать в сторону atexit()?

    Да. И читать Александреску

    SDB>
  • Я правильно понимаю, что реализовать singleton для класса, который не имеет конструктора по умолчанию, невозможно?

    Возможно, например, использованием трейтов на создание экземпляра.

    struct MyCreator
    {
       type *Create()
       {
            return new Type(params)
    //      или (тут надо осторожнее, чтобы компилятор не принял след. строку за объявление функции)
            static Type t(params);
            return &t;          
       }
       Destroy(type *t)
       {
    //   etc
       }
    }


    Вообще, тут надо _обязательно_ использовать трейты. А лучше взять синглтон из локи и покромсать его под свои нужды. Там все было прозрачно.

    PS
    Синглтон — это очень неоднозначная штука. Если можно обойтись без него — например, просто объявить глобальную переменную — то лучше это сделать. Паттераны и т.п. — это все красиво. В теории. Но жизнь, как обычно, вносит свои коррективы.
  • http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: Потоко-бесопасный синглетон
    От: Аноним  
    Дата: 05.10.06 07:07
    Оценка:
    Здравствуйте, Аноним, Вы писали:

    А>Здравствуйте, SchweinDeBurg, Вы писали:


    А>Рекомендую, хорошая книжка

    А>Design Patterns Explained: A New Perspective on Object-Oriented Design
    А>By Alan Shalloway, James R. Trott

    А>ftp://files.zipsites.ru/books/edocs/Addison_Wesley/Design.Patterns.Explained.A.New.Perspective.on.Object.Oriented.Design.2nd.Edition..chm


    А>Размер 1,6 Мб



    А>Выдержка оттуда:


    А>Example 16-4 C++ Code Fragment: Double-Checked Locking Pattern

    А>
    А>class USTax : public CalcTax {
    А>  public:
    А>    static USTax* getInstance();
    А>  private:
    А>    USTax();
    А>    static USTax* instance;
    А>};
    А>USTax* USTax::instance= 0;
    
    А>USTax* USTax::getInstance () {
    А>  if (instance== 0) {
    А>    // do sync here
    А>    if (instance== 0) {
    А>        instance= new USTax;
    А>    }
    А>  }
    А>  return instance;
    А>}
    А>


    Ну, сколько можно ....
    http://www.javaworld.com/jw-02-2001/jw-0209-double.html
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.