Возможно (... да, верно) решено: дважды проверил блокировку на C++: новичок в указателе температуры, затем назначить его экземпляру
Это продолжение этого поста о двойной проверке блокировки. Я пишу новое сообщение, потому что кажется, что публикация продолжения "старых" сообщений не делает его таким же видимым / активным, как отправка нового сообщения, возможно, потому, что большинство людей не сортируют сообщения в stackru по уровню активности,
Всем, кто ответил, спасибо за ваш вклад в оригинальный пост. Посмотрев замечательную книгу Джо Даффи "Параллельное программирование в Windows", я подумал, что мне следует использовать приведенный ниже код. Он во многом идентичен коду из его книги, за исключением некоторых переменных переименований и строки InterlockedXXX. Следующая реализация использует:
- ключевое словоvolatile как на временные, так и на "фактические" указатели для защиты от повторного упорядочивания компилятором.
- InterlockedCompareExchangePointer для защиты от переупорядочения с процессором.
Итак, это должно быть довольно безопасно (... верно?):
template <typename T>
class LazyInit {
public:
typedef T* (*Factory)();
LazyInit(Factory f = 0)
: factory_(f)
, singleton_(0)
{
::InitializeCriticalSection(&cs_);
}
T& get() {
if (!singleton_) {
::EnterCriticalSection(&cs_);
if (!singleton_) {
T* volatile p = factory_();
// Joe uses _WriterBarrier(); then singleton_ = p;
// But I thought better to make singleton_ = p atomic (as I understand,
// on Windows, pointer assignments are atomic ONLY if they are aligned)
// In addition, the MSDN docs say that InterlockedCompareExchangePointer
// sets up a full memory barrier.
::InterlockedCompareExchangePointer((PVOID volatile*)&singleton_, p, 0);
}
::LeaveCriticalSection(&cs_);
}
#if PREVENT_IA64_FROM_REORDERING
_ReadBarrier();
#endif
return *singleton_;
}
virtual ~LazyInit() {
::DeleteCriticalSection(&cs_);
}
private:
CRITICAL_SECTION cs_;
Factory factory_;
T* volatile singleton_;
};
1 ответ
Я всегда использовал гораздо более простой шаблон синглтона.
class CSomething
{
protected:
CSomething() {};
public:
~CSomething() {};
static CSomething *Get()
{
static CSomething s;
return &s;
}
// Rest of the class
};