Креш в синглтоне Мейерса
От: Станислав Артемкин  
Дата: 22.11.07 11:45
Оценка: 13 (5)
Всем привет,

Возможно будет полезно. Следующая имплементация падает в релизной версии, скомпилированной MSVC++. Это дефект оптимизатора MSVC++.

Foo.h
----------
class Foo
{
public:
   static Foo& GetInstance()
   {
      static Foo instance;
      return instance;
   }
};


Исправлял уже 2 раза в нашем проекте.

Чтобы исправить надо перенести имплементацию метода GetInstance() в cpp-шник. Чтобы понять почему падает, добавьте счетчик созданных объектов в Foo и подивитесь

Кое какая информация есть здесь:
http://www.codeproject.com/useritems/VC2003MeyersSingletonBug.asp
Стас
Re: Креш в синглтоне Мейерса
От: Bell Россия  
Дата: 22.11.07 12:10
Оценка:
Здравствуйте, Станислав Артемкин, Вы писали:

Старая беда.
Тянется еще с MSVC6.
Обсуждалась, например, здесь
Автор: Tuo_Bellas
Дата: 28.03.03
Любите книгу — источник знаний (с) М.Горький
Re: Креш в синглтоне Мейерса
От: remark Россия http://www.1024cores.net/
Дата: 22.11.07 13:12
Оценка:
Здравствуйте, Станислав Артемкин, Вы писали:

СА>Чтобы исправить надо перенести имплементацию метода GetInstance() в cpp-шник. Чтобы понять почему падает, добавьте счетчик созданных объектов в Foo и подивитесь


А если линкер заинлайнит, то тоже будет работать?


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Креш в синглтоне Мейерса
От: Andrew S Россия http://alchemy-lab.com
Дата: 22.11.07 21:35
Оценка:
СА>Возможно будет полезно. Следующая имплементация падает в релизной версии, скомпилированной MSVC++. Это дефект оптимизатора MSVC++.

СА>Чтобы исправить надо перенести имплементацию метода GetInstance() в cpp-шник. Чтобы понять почему падает, добавьте счетчик созданных объектов в Foo и подивитесь


СА>Кое какая информация есть здесь:

СА>http://www.codeproject.com/useritems/VC2003MeyersSingletonBug.asp

Очень странный баг. Как уже замечал ПК в топике, указанном выше, очень многое из std просто не работало бы в этом случае.
Я проверил на 6-ке и 7.1 (на остальных просто лениво проверять) — все нормально. Мысли?

PS вот что сделал VC7:

/////////////////////////////////////////////////////  global
?GetInstance@Foo@@SAAAV1@XZ PROC NEAR            ; Foo::GetInstance, COMDAT

; 361  :       static Foo instance;
; 362  :       return instance;

    mov    eax, OFFSET FLAT:?instance@?1??GetInstance@Foo@@SAAAV2@XZ@4V2@A ; `Foo::GetInstance'::`2'::instance

; 363  :    }

    ret    0

////////////////////////////////////////////////////// main module

; 374  :     printf("%p\n", &Foo::GetInstance());

    push    OFFSET FLAT:?instance@?1??GetInstance@Foo@@SAAAV2@XZ@4V2@A ; `Foo::GetInstance'::`2'::instance
    push    OFFSET FLAT:??_C@_03OHEJPPDF@?$CFp?6?$AA@
    mov    DWORD PTR __$EHRec$[esp+56], 0
    call    _printf
////////////////////////////////////////////////////// slave module
?f_f@@YAXXZ PROC NEAR                    ; f_f, COMDAT

; 17   :     printf("%p\n", &Foo::GetInstance());

    push    OFFSET FLAT:?instance@?1??GetInstance@Foo@@SAAAV2@XZ@4V2@A ; `Foo::GetInstance'::`2'::instance
    push    OFFSET FLAT:??_C@_03OHEJPPDF@?$CFp?6?$AA@
    call    _printf
    add    esp, 8

; 18   : }

    ret    0


Т.е. все ОК, как и ожидалось. Сформировалась никому не нужная Foo::GetInstance (которую затем выкинет линкер), и один глобальный объект класса Foo, который инициализируется как статический объект (видимо, потому что не имеет конструкторов, которые бы имели видимые последствия). Может, пример должен быть несколько сложнее?
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re: Креш в синглтоне Мейерса
От: COFF  
Дата: 23.11.07 08:18
Оценка:
СА>Исправлял уже 2 раза в нашем проекте.

СА>Чтобы исправить надо перенести имплементацию метода GetInstance() в cpp-шник. Чтобы понять почему падает, добавьте счетчик созданных объектов в Foo и подивитесь


Действительно странно. А в какой конкретно момент падает? При первом обращении, при выходе из программы или еще где-то? Если при выходе из программы, то это может быть связано с неопределенным порядком деинициализации статических объектов в C++. При переносе в cpp этот порядок вполне может поменяться.
Re: Креш в синглтоне Мейерса
От: Erop Россия  
Дата: 23.11.07 08:46
Оценка:
Здравствуйте, Станислав Артемкин, Вы писали:

СА>Чтобы исправить надо перенести имплементацию метода GetInstance() в cpp-шник. Чтобы понять почему падает, добавьте счетчик созданных объектов в Foo и подивитесь


СА>Кое какая информация есть здесь:

СА>http://www.codeproject.com/useritems/VC2003MeyersSingletonBug.asp

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

А такая конструкция помогает?
class Foo
{
public:
   static Foo& GetInstance()
   {
      static Foo* p = 0;
      if( p == 0 ) {
         static Foo instance;
         p = &instance;
      }
      return *p;
   }
};


Кстати, такой ещё вопрос небанальный, а это случаем не воссоздание синглетона после его разрушения происходит?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Креш в синглтоне Мейерса
От: AntiFreeze  
Дата: 23.11.07 18:54
Оценка:
Здравствуйте, Andrew S, Вы писали:

AS>Очень странный баг. Как уже замечал ПК в топике, указанном выше, очень многое из std просто не работало бы в этом случае.


А что именно в std использует такие синглтоны?
Re[2]: Креш в синглтоне Мейерса
От: Sni4ok  
Дата: 23.11.07 22:37
Оценка: :)
Здравствуйте, COFF, Вы писали:



COF>Действительно странно. А в какой конкретно момент падает? При первом обращении, при выходе из программы или еще где-то?


когда 2 нитки заходят одновременно в instance, при этом instance ранее ещё не вызывалось, чего тут не понятного?
Re[3]: Креш в синглтоне Мейерса
От: COFF  
Дата: 25.11.07 19:46
Оценка: :)
Здравствуйте, Sni4ok, Вы писали:

S>когда 2 нитки заходят одновременно в instance, при этом instance ранее ещё не вызывалось, чего тут не понятного?


Это откуда, извините, следует?
Re: Креш в синглтоне Мейерса
От: qwerty2006  
Дата: 27.11.07 07:58
Оценка:
Здравствуйте, Станислав Артемкин, Вы писали:

СА>Всем привет,

СА>Возможно будет полезно. Следующая имплементация падает в релизной версии, скомпилированной MSVC++. Это дефект оптимизатора MSVC++.
......

У меня абсолютно такая же проблема. Никакого multithreading. Баги лезли из разных мест, пока не заметил, что c'tor и d'tor вызываются по неск. раз.
Спасло перемещение реализации в CPP.
MS VC SP1 (v7.1.6030).
Re[2]: Креш в синглтоне Мейерса
От: krokodil955  
Дата: 27.11.07 08:38
Оценка:
да, я тоже юзал эту реализацию (брал один в один с Эккеля), правда компилер g++, — тоже были баги
взял реализацию из БЧ — проблемы вроде исчезли (приложение кстати multithreading).
Re: Креш в синглтоне Мейерса
От: Sergipu  
Дата: 27.11.07 09:01
Оценка: -1
Здравствуйте, Станислав Артемкин, Вы писали:

СА>Всем привет,


СА>Возможно будет полезно. Следующая имплементация падает в релизной версии, скомпилированной MSVC++. Это дефект оптимизатора MSVC++.


СА>
СА>Foo.h
СА>----------
СА>class Foo
СА>{
СА>public:
СА>   static Foo& GetInstance()
СА>   {
СА>      static Foo instance;
СА>      return instance;
СА>   }
СА>};
СА>


На мой взгляд — ничего удивительного не происходит. Статическая ф-я GetInstance() инлайнится в 2 модуля компиляции вместе со своей статической переменной. 2 разные переменные — разные и значения. Другое дело, насколько такое поведение комилятора соответсвует стандарту... Мне кажется, что вполне, но если кто-то докажет обратное — буду благодарен за ценную инфу. )))
Re[2]: Креш в синглтоне Мейерса
От: Bell Россия  
Дата: 27.11.07 09:05
Оценка:
Здравствуйте, Sergipu, Вы писали:

S>На мой взгляд — ничего удивительного не происходит.

Кому как

S>Статическая ф-я GetInstance() инлайнится в 2 модуля компиляции вместе со своей статической переменной. 2 разные переменные — разные и значения. Другое дело, насколько такое поведение комилятора соответсвует стандарту... Мне кажется, что вполне, но если кто-то докажет обратное — буду благодарен за ценную инфу. )))


7.1.2/4
...
An inline function with external linkage shall have the same address in all translation units. A static
local variable in an extern inline function always refers to the same object.
A string literal in an
extern inline function is the same object in different translation units.

Любите книгу — источник знаний (с) М.Горький
Re[2]: Креш в синглтоне Мейерса
От: Andrew S Россия http://alchemy-lab.com
Дата: 27.11.07 09:10
Оценка:
S>На мой взгляд — ничего удивительного не происходит. Статическая ф-я GetInstance() инлайнится в 2 модуля компиляции вместе со своей статической переменной. 2 разные переменные — разные и значения. Другое дело, насколько такое поведение комилятора соответсвует стандарту... Мне кажется, что вполне, но если кто-то докажет обратное — буду благодарен за ценную инфу. )))

Ну вот я привел код — инлайнится, но экземпляр — один. По поводу "соответствия" уже сказали, но указанное поведение и не воспроизводится. Может, дело в настройках? Хорошо бы настройки компилера и линкера, или просто проект, который это дело явно воспроизводит.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[3]: Креш в синглтоне Мейерса
От: Erop Россия  
Дата: 27.11.07 09:40
Оценка:
Здравствуйте, Andrew S, Вы писали:

AS>Ну вот я привел код — инлайнится, но экземпляр — один. По поводу "соответствия" уже сказали, но указанное поведение и не воспроизводится. Может, дело в настройках? Хорошо бы настройки компилера и линкера, или просто проект, который это дело явно воспроизводит.


Может быть стоит ключик оптимизации "передполагать, что нет двух ссылок на одну переменную"?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Креш в синглтоне Мейерса
От: Andrew S Россия http://alchemy-lab.com
Дата: 27.11.07 10:16
Оценка:
AS>>Ну вот я привел код — инлайнится, но экземпляр — один. По поводу "соответствия" уже сказали, но указанное поведение и не воспроизводится. Может, дело в настройках? Хорошо бы настройки компилера и линкера, или просто проект, который это дело явно воспроизводит.

E>Может быть стоит ключик оптимизации "передполагать, что нет двух ссылок на одну переменную"?


Вот ключи:
cl /EHsc /GX /O2 /Op /FAs /FD /D "WIN32" /D "_CONSOLE" /c
link kernel32.lib user32.lib /subsystem:console /incremental:no /release

Версии:
cl: 13.10.3077
link: 7.10.3077
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[3]: Креш в синглтоне Мейерса
От: Аноним  
Дата: 27.11.07 10:23
Оценка:
Здравствуйте, Bell, Вы писали:

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


S>>На мой взгляд — ничего удивительного не происходит.

B>Кому как

S>>Статическая ф-я GetInstance() инлайнится в 2 модуля компиляции вместе со своей статической переменной. 2 разные переменные — разные и значения. Другое дело, насколько такое поведение комилятора соответсвует стандарту... Мне кажется, что вполне, но если кто-то докажет обратное — буду благодарен за ценную инфу. )))


B>

B>7.1.2/4
B>...
B>An inline function with external linkage shall have the same address in all translation units. A static
B>local variable in an extern inline function always refers to the same object.
A string literal in an
B>extern inline function is the same object in different translation units.

А можно заодно объяснить почему Foo::GetInstance() имеет external linkage? Потому что класс Foo имеет external linkage?
Изменится что-нибудь если GetInstance() будет свободной глобальной или в неймспейсе static inline функцией?
Re[4]: Креш в синглтоне Мейерса
От: Erop Россия  
Дата: 27.11.07 10:29
Оценка:
Здравствуйте, Аноним, Вы писали:


А>Изменится что-нибудь если GetInstance() будет в неймспейсе static inline функцией?

Да, тогда каждый объект будет уникальным
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Креш в синглтоне Мейерса
От: Bell Россия  
Дата: 27.11.07 11:10
Оценка:
Здравствуйте, Аноним, Вы писали:

А>А можно заодно объяснить почему Foo::GetInstance() имеет external linkage? Потому что класс Foo имеет external linkage?

Да.

3.5/4
A name having namespace scope has external linkage if it is the name of
...
— a named class (clause 9), or an unnamed class defined in a typedef declaration in which the class has the
typedef name for linkage purposes (7.1.3); or
...

3.5/5
In addition, a member function, static data member, class or enumeration of class scope has external linkage
if the name of the class has external linkage.



А>Изменится что-нибудь если GetInstance() будет свободной глобальной или в неймспейсе static inline функцией?

Да, в этом случае GetInstance будет internal, т.е. в каждой единице трансляции у этой функции будет своя копия статического объекта:

3.5/3
A name having namespace scope (3.3.5) has internal linkage if it is the name of
— an object, reference, function or function template that is explicitly declared static or,
...

Любите книгу — источник знаний (с) М.Горький
Re[5]: Креш в синглтоне Мейерса
От: Аноним  
Дата: 27.11.07 12:28
Оценка:
Здравствуйте, Bell, Вы писали:

А>>А можно заодно объяснить почему Foo::GetInstance() имеет external linkage? Потому что класс Foo имеет external linkage?

B>Да.
[]

А>>Изменится что-нибудь если GetInstance() будет свободной глобальной или в неймспейсе static inline функцией?

B>Да, в этом случае GetInstance будет internal, т.е. в каждой единице трансляции у этой функции будет своя копия статического объекта:
[]

Спасибо. А если GetInstance будет internal, то её адрес и сам код тоже, как и её статические данные, будут свои для каждой единицы трансляции? То есть полный копи/паст? Или это уже от компилятора зависит?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.