Re: thread safe singlton - возможно ли такое в принципе
От: WolfHound  
Дата: 06.02.04 13:50
Оценка: 18 (3)
Здравствуйте, Andrew S, Вы писали:

Толком не тестировал но по идеи так
LONG atom_set(volatile LONG* ptr, LONG value)
{
    return InterlockedExchange(ptr, value);
}
LONG atom_get(volatile LONG* ptr)
{
    return InterlockedExchangeAdd(ptr, 0);
}
struct auto_lock
{
    auto_lock(LONG* ptr)
        :ptr_(ptr)
    {
        while(atom_set(ptr_, 1))
            Sleep(1);
    }
    ~auto_lock()
    {
        atom_set(ptr_, 0);
    }
    LONG* ptr_;
};
template<class T>
struct MTSingleton
{
    static T &Instance()
    {
        static T* obj_ptr=0;//Статическая инициализация(потокобезопасно)
        static LONG flag=0;//Аналогично
        T* ptr=(T*)atom_get((LONG*)&obj_ptr);
        if(!ptr)
        {
            auto_lock lock(&flag);
            ptr=(T*)atom_get((LONG*)&obj_ptr);
            if(!ptr)
            {
                static T obj;//Создастся пи первом поподании сюда
                ptr=&obj;
                atom_set((LONG*)&obj_ptr, (LONG)ptr);
            }
        }
        return *ptr;
    }
};
struct test_singleton
    :MTSingleton<test_singleton>
{
    test_singleton()
    {
    }
};
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[9]: thread safe singlton - возможно ли такое в принципе
От: Павел Кузнецов  
Дата: 22.06.04 16:38
Оценка: 10 (2)
>

> For the P6 family processors, locked operations serialize all outstanding load and store operations (that is, wait for them to complete). This rule is also true for the Pentium 4 and Intel Xeon processors, with one exception: load operations that reference weakly ordered memory types (such as the WC memory type) may not be serialized.

>
> Из этого куска следует, что lock для семейства P6 наконец-то начинает работать как memory barrier

Да, именно это я и имел в виду.

> но как быть с P5 и 486-386?


Эти процессоры не переупорядочивают запись, так что им memory barrier не нужен, достаточно атомарности изменений.
Posted via RSDN NNTP Server 1.9 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[4]: thread safe singlton - возможно ли такое в принципе
От: Andrew S Россия http://alchemy-lab.com
Дата: 06.02.04 15:21
Оценка: +1
AS>>2. Медленно.
V>А если вот так?

V>
V>static MeyersSingleton &Instance()
V>    {
V>        bool instantiated=false;
V>        if (!instaniated) {  
V>           HANDLE h;
V>           h=CreateMutex(NULL, true, "mutext");
V>           static MeyersSingleton obj;
V>           instantiated=true;
V>           ReleaseMutex(h);
V>           CloseHandle(h);
V>        } 
V>        return obj;
V>    }
V>


И так медленно И неправильно.
1. static volatile bool
2. объвлять его членом класса.
3. Не скомпилируется — obj out of scope.
4. Создание объекта для надежности в отдельную статическую функцию (дабы не искушать оптимизатор).
5. Двойная проверка некорректно работает на некоторых SMP системах. Вообще ее не рекомендуют использовать — то там баг отловится, то там...

В общем, работающее решение предложил WolfHound, но мне оно по ряду причин не нравится и рекомендовать его к использованию я не могу. Но оно рабочее и даже в некотором смысле кошерное.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[10]: thread safe singlton - возможно ли такое в принципе
От: Павел Кузнецов  
Дата: 22.06.04 18:55
Оценка: +1
>>> чтение тоже может быть переупорядочено. <...> Чтобы проблемы не было надо ставить acquire lock после atom_get, а InterlockedExchangeAdd, через который реализован atom_get этого не делает.
>
> ПК>Если я правильно понял MSDN, то должен делать там, где это нужно...
>
> http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/interlockedexchange64.asp
> Вроде ни слова про барьеры.

Внизу странички ссылка: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/synchronization_and_multiprocessor_issues.asp

Processors can be instructed to force their memory caches to agree with main memory with special instructions. Such instructions ensure that previous read and write requests have completed and are made visible to other processors, and to ensure that that no subsequent read or write requests have started. Examples are:

  • Functions which enter or leave critical sections.
  • Functions which signal synchronization objects.
  • Wait functions.
  • Interlocked functions

    <...>

    The InterlockedExchange function ensures that the value of iValue is updated for all processors before the value of fValueHasBeenComputed is set to TRUE.

  • Это и есть неформальное описание memory barrier.
    Posted via RSDN NNTP Server 1.9 beta
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[6]: Вопрос.
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 09.07.04 10:14
    Оценка: +1
    _>>Спросил только для того что бы получше понять смысл написанного. Человек я простой, только простые вещи понимаю. Насколько я понимаю, все будет работать даже так:
    WH>хъ
    _>>Правильно?
    WH>А вот тут нет memory barrier(он встроен в InterlockedXXX функции). Так что теоритически могут быть проблемы.

    Почему нет?
    struct auto_lock
    {
        auto_lock(LONG* ptr)
            :ptr_(ptr)
        {
            while(atom_set(ptr_, 1))
                Sleep(1);
        }
        ~auto_lock()
        {
            atom_set(ptr_, 0);
        }
        LONG* ptr_;
    };

    Имхо, просто этот код тормознее, поскольку возможны конфликты, и, соотв, попадание в sleep при одновременном входе из разных потоков... Двойная проверка как раз делается для того, чтобы быстрее было. А выше был приведен классический "медленный" вариант. Любоай auto_lock, предоставляемый средствами OS, должен являться memmory barrier.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[17]: thread safe singlton - возможно ли такое в принципе
    От: Lexey Россия  
    Дата: 19.07.04 20:05
    Оценка: +1
    Здравствуйте, Andrew S, Вы писали:

    L>>Это как раз совершенно не серьезное преимущество.

    L>>В общем, я могу предложить вариант, который наверное устроит и тебя и меня.
    L>>Сделать синглетон-критическую секцию, создание которой защитить lightweight_mutex'ом (создание тут быстрое, так что можно). И вот эту критическую секцию и использовать при инициализации остальных синглетонов.

    AS>Одну критическую секция на все? Несерьезно, тормоза будут дикие, более того может


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

    AS> быть так, что создание одного синглтона зависит от другого, и это происходит в разных потоках. Придется все-равно по одному именованному объекту на синглтон. Мне кажется, это не очень хорошая мысль. А точнее, очень _не_ хорошая. Впрочем, каждому


    А где ты в критической секции увидел именованные объекты?

    AS> свое

    AS>В любом случае, серебряной пули не существует...

    Это верно.
    ... << RSDN@Home 1.1.4 beta 1 >>
    "Будь достоин победы" (c) 8th Wizard's rule.
    thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 06.02.04 13:07
    Оценка:
    Всем доброго времени суток.
    Итак, как было выяснено здесь
    Автор: Andrew S
    Дата: 06.02.04
    , синглтон Майерса не является потокобезопасным.


    struct MeyersSingleton
    {
        static MeyersSingleton &Instance()
        {
            static MeyersSingleton obj;
            return obj;
        }
    ================
        mov    al, BYTE PTR ?$S223@?1??Instance@?$CMeyersSingleton@VCNetworkSession@@@@SAAAVCNetworkSession@@XZ@4EA
        mov    BYTE PTR __$EHRec$[esp+80], 4
        test    al, 1
        jne    SHORT $L90959
        or    al, 1
        push    10                    ; 0000000aH
        mov    ecx, OFFSET FLAT:?obj@?1??Instance@?$CMeyersSingleton@VCNetworkSession@@@@SAAAVCNetworkSession@@XZ@4U2@A
        mov    BYTE PTR ?$S223@?1??Instance@?$CMeyersSingleton@VCNetworkSession@@@@SAAAVCNetworkSession@@XZ@4EA, al
        push    OFFSET FLAT:?obj@?1??Instance@?$CMeyersSingleton@VCNetworkSession@@@@SAAAVCNetworkSession@@XZ@$AU1@A ; obj
        call    _atexit
        add    esp, 4
    $L90959:
    
    ================
    private:
        MeyersSingleton(){};
        MeyersSingleton(const MeyersSingleton &);
        MeyersSingleton & operator = (const MeyersSingleton &);
        ~MeyersSingleton(){};
    };



    Первое, что я подумал — сделать синглтон на хипе, создание защитить критическими секциями. Однако, критические секции (ну или мутексы, какая разница...) перед использованием надо инициализировать. Но, поскольку для синхронизации нам надо уже иметь проинициализированной критическую секкцию, опять приходим к идиоме синглтона майерса (уже для инициализации критической секции) со всем вытекающими проблемами потоконебезопасности.
    Какие варианты подскажет уважаемая общественность?
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re: thread safe singlton - возможно ли такое в принципе
    От: ArtDenis Россия  
    Дата: 06.02.04 13:20
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Итак, как было выяснено здесь
    Автор: Andrew S
    Дата: 06.02.04
    , синглтон Майерса не является потокобезопасным.


    У Александреску есть хороший потокобезопасный синглтон.
    ... << RSDN@Home 1.1.2 stable >>
    [ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
    Re: thread safe singlton - возможно ли такое в принципе
    От: Вадим Никулин Россия Здесь
    Дата: 06.02.04 13:42
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Всем доброго времени суток.

    AS>Итак, как было выяснено здесь
    Автор: Andrew S
    Дата: 06.02.04
    , синглтон Майерса не является потокобезопасным.



    AS>
    AS>struct MeyersSingleton
    AS>{
    AS>    static MeyersSingleton &Instance()
    AS>    {
               Lock lock;                        // А что мешает блокировку вставить?
               {
    AS>           static MeyersSingleton obj;
    AS>           return obj;
               }
    AS>    }
    AS>

    AS>Какие варианты подскажет уважаемая общественность?
    Не совсем понятно, почему студия должна генерить потоко-независимый код. Если бы она это делала, то какая была бы эффективность этого кода? Об этом должен заботиться разработчик.
    Re[2]: thread safe singlton - возможно ли такое в принципе
    От: Вадим Никулин Россия Здесь
    Дата: 06.02.04 13:49
    Оценка:
    Здравствуйте, Вадим Никулин, Вы писали:

    ВН>Здравствуйте, Andrew S, Вы писали:


    AS>>Всем доброго времени суток.

    AS>>Итак, как было выяснено здесь
    Автор: Andrew S
    Дата: 06.02.04
    , синглтон Майерса не является потокобезопасным.



    AS>>
    AS>>struct MeyersSingleton
    AS>>{
    AS>>    static MeyersSingleton &Instance()
    AS>>    {
    ВН>           Lock lock;                        // А что мешает блокировку вставить?
    ВН>           {
    AS>>           static MeyersSingleton obj;
    AS>>           return obj;
    ВН>           }
    AS>>    }
    AS>>

    AS>>Какие варианты подскажет уважаемая общественность?
    ВН>Не совсем понятно, почему студия должна генерить потоко-независимый код. Если бы она это делала, то какая была бы эффективность этого кода? Об этом должен заботиться разработчик.

    Да, забыл сказать, мьютекс можно создать без проблем, т. к. если два потока одновременно попытаются создать мьютексы с одинаковым именем, один из них получит отказ, и должен будет проверить, а не создан ли мьютекс пока он его создавал. Если да, то его просто нужно открыть.
    Re[2]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 06.02.04 13:54
    Оценка:
    AS>>Итак, как было выяснено здесь
    Автор: Andrew S
    Дата: 06.02.04
    , синглтон Майерса не является потокобезопасным.


    AD>У Александреску есть хороший потокобезопасный синглтон.


    Нет у него _работающего_ потокобезопасного синглетона, к сожалению. То, что есть — основывается на том, что критическая секция инициализируется в конструкторе синглетона. А тот, в свою очередь, статически создается в cpp файле. Тогда уже можно и целевой объект статически создавать в cpp файле, напарываясь при этом на неопределенность инициализации статических объектов в разных модулях. За что боролись, на то и напоролись.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[3]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 06.02.04 13:57
    Оценка:
    ВН>>Не совсем понятно, почему студия должна генерить потоко-независимый код. Если бы она это делала, то какая была бы эффективность этого кода? Об этом должен заботиться разработчик.

    Ну, этот код вызывается один раз при первом вызове функции — эффективность не сильно пострадала бы. А вот нервы разработчика — точно были бы целее.

    ВН>Да, забыл сказать, мьютекс можно создать без проблем, т. к. если два потока одновременно попытаются создать мьютексы с одинаковым именем, один из них получит отказ, и должен будет проверить, а не создан ли мьютекс пока он его создавал. Если да, то его просто нужно открыть.


    Верно, но это только для именованых мьютексов. Представляете, какая производительность такого кода будет?
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 06.02.04 14:05
    Оценка:
    
    WH>    auto_lock(LONG* ptr)
    WH>        :ptr_(ptr)
    WH>    {
    WH>        while(atom_set(ptr_, 1))
    WH>            Sleep(1);
    WH>    }


    Честно говоря, я так и думал, что будут советовать нечто в этом роде
    Я сам рассматривал возможность синхронизации через семейство Interlockedxxx функций, но, согласитесь, выглядит это по меньшей мере страшненько (на самом деле я бы такой код в проекте не допустил, уж лучше инициализировать синглетон статически в файле реализации и потерять безопасность на этапе конструирования статических объектов — т.е. гарантировать, что на этом этапе вызова Instance не будет. Это проще и безопаснее, чем написать такое решение...). Но за попытку спасибо!
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[3]: thread safe singlton - возможно ли такое в принципе
    От: WolfHound  
    Дата: 06.02.04 14:15
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Я сам рассматривал возможность синхронизации через семейство Interlockedxxx функций, но, согласитесь, выглядит это по меньшей мере страшненько (на самом деле я бы такой код в проекте не допустил, уж лучше инициализировать синглетон статически в файле реализации и потерять безопасность на этапе конструирования статических объектов — т.е. гарантировать, что на этом этапе вызова Instance не будет. Это проще и безопаснее, чем написать такое решение...). Но за попытку спасибо!

    Чем лучше? Я эту идею из boost позаимствовал...
    ... << RSDN@Home 1.1.3 beta 1 >>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re: thread safe singlton - возможно ли такое в принципе
    От: Павел Кузнецов  
    Дата: 06.02.04 14:23
    Оценка:
    Здравствуйте, Andrew, Вы писали:

    AS> Первое, что я подумал — сделать синглтон на хипе, создание

    AS> защитить критическими секциями.

    Не обязательно создавать объект singleton в динамической памяти. Достаточно
    предварить определение статического объекта захватом мьютекса или критической
    секции.

    AS> Однако, критические секции (ну или мутексы, какая разница...) перед

    AS> использованием надо инициализировать.

    Один из вариантов — инициализировать критическую секцию/мьютекс заведомо до
    использования singleton.

    Если структура программы настолько аморфна, что ничего о времени использования
    тех или иных объектов сказать нельзя, возможно, стоит задуматься об архитектуре.
    Posted via RSDN NNTP Server 1.7 "Bedlam"
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[4]: thread safe singlton - возможно ли такое в принципе
    От: unrealalex Россия  
    Дата: 06.02.04 14:25
    Оценка:
    WH>Я эту идею из boost позаимствовал...
    если мне память не изменяет, то из lightweight_mutex... только я бы Sleep(0) оставил — так квант отдаеться, а в твоем случае задержка, хоть и маленькая.
    Невозможное мы сделаем сегодня — чудо займет немного больше времени. /Аноним/
    Re[2]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 06.02.04 14:27
    Оценка:
    ПК>Один из вариантов — инициализировать критическую секцию/мьютекс заведомо до
    ПК>использования singleton.

    Верно. Например, в файле реализации синглетона, как это сделано у Александреску.
    Но тогда возможна ситуация вызова Instance с еще непроинициализированной критической секцией. В общем, за что боролись... Печально, Павел, неужели нет красивого выхода из этой ситауции?

    ПК>Если структура программы настолько аморфна, что ничего о времени использования

    ПК>тех или иных объектов сказать нельзя, возможно, стоит задуматься об архитектуре.
    Нет, меня вполне устраивает объявление объекта синглтона в файле реализации и я могу гарантировать, что Instance будет вызываться только после инициализации статических объектов. Но меня интересует не конкретный проект, а именно принцип.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 06.02.04 14:30
    Оценка:
    AS>>Я сам рассматривал возможность синхронизации через семейство Interlockedxxx функций, но, согласитесь, выглядит это по меньшей мере страшненько (на самом деле я бы такой код в проекте не допустил, уж лучше инициализировать синглетон статически в файле реализации и потерять безопасность на этапе конструирования статических объектов — т.е. гарантировать, что на этом этапе вызова Instance не будет. Это проще и безопаснее, чем написать такое решение...). Но за попытку спасибо!
    WH>Чем лучше? Я эту идею из boost позаимствовал...
    Ну, мы люди темные, бустом не пользуемся Но такой вариант я придумал сразу и отверг его, содрогнувшись в душе.
    Как говорил Туполев — некрасивый самолет не полетит.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[5]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 06.02.04 14:31
    Оценка:
    WH>>Я эту идею из boost позаимствовал...
    U>если мне память не изменяет, то из lightweight_mutex... только я бы Sleep(0) оставил — так квант отдаеться, а в твоем случае задержка, хоть и маленькая.

    Нет, это ошибка в MSDN. Квант то отдается, а вот загрузка процесса — становится максимальной.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re: thread safe singlton - возможно ли такое в принципе
    От: Vamp Россия  
    Дата: 06.02.04 14:38
    Оценка:
    Наверное, я чего-то не понимаю. А почему нельзя просто

    AS>
    AS>struct MeyersSingleton
    AS>{
    AS>    static MeyersSingleton &Instance()
    AS>    {
    AS>        HANDLE h;
               CreateMutex(NULL, true, "mutext");
               static MeyersSingleton obj;
               ReleaseMutex(h);
    AS>        return obj;
    AS>    }
    ...
    AS>

    Виндоус-компилятора нет, проверить не могу — но любопытно.
    Да здравствует мыло душистое и веревка пушистая.
    Re[3]: thread safe singlton - возможно ли такое в принципе
    От: Павел Кузнецов  
    Дата: 06.02.04 14:39
    Оценка:
    Здравствуйте, Andrew, Вы писали:

    AS> Нет, меня вполне устраивает объявление объекта синглтона в

    AS> файле реализации и я могу гарантировать, что Instance
    AS> будет вызываться только после инициализации статических объектов.
    AS> Но меня интересует не конкретный проект, а именно принцип.

    Боюсь, что более-менее общим принципом будет как раз архитектура, позволяющая
    отделить инициализацию вспомогательных ресурсов (в данном случае критическая
    секция) от инициализации и использования основных объектов (синглтон)... Думаю,
    что "локального" платформенно-независимого решения, прозрачного для использующей
    программы, нет.
    Posted via RSDN NNTP Server 1.7 "Bedlam"
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[2]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 06.02.04 14:48
    Оценка:
    AS>>
    AS>>struct MeyersSingleton
    AS>>{
    AS>>    static MeyersSingleton &Instance()
    AS>>    {
    AS>>        HANDLE h;
    V>           CreateMutex(NULL, true, "mutext");
    V>           static MeyersSingleton obj;
    V>           ReleaseMutex(h);
    AS>>        return obj;
    AS>>    }
    V>...
    AS>>

    V>Виндоус-компилятора нет, проверить не могу — но любопытно.

    Мысль правильная, реализация — нет.
    1. Хэндл не присваивается и не закрывается
    2. Медленно.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[3]: thread safe singlton - возможно ли такое в принципе
    От: Vamp Россия  
    Дата: 06.02.04 14:56
    Оценка:
    AS>Мысль правильная, реализация — нет.
    AS>1. Хэндл не присваивается и не закрывается
    Ну, это понятно. Замнем для ясности.
    AS>2. Медленно.
    А если вот так?

    static MeyersSingleton &Instance()
        {
            bool instantiated=false;
            if (!instaniated) {  
               HANDLE h;
               h=CreateMutex(NULL, true, "mutext");
               static MeyersSingleton obj;
               instantiated=true;
               ReleaseMutex(h);
               CloseHandle(h);
            } 
            return obj;
        }
    Да здравствует мыло душистое и веревка пушистая.
    Re[2]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 06.02.04 16:08
    Оценка:
    Кстати, вот этот код абсолютно бесполезен:

    WH>
    WH>LONG atom_get(volatile LONG* ptr)
    WH>{
    WH>    return InterlockedExchangeAdd(ptr, 0);
    WH>}
    WH>


    Просто читая volatile переменную типа int или long на win32 мы гарантированно получаем валидное значение (старое или новое — вопрос другой, но валидное). Т.о. приведенный код ровным счетом ничего не делает. Так утверждают и господин Рихтер, да и многие другие, и я склонен с ними соглашаться.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[5]: thread safe singlton - возможно ли такое в принципе
    От: Vamp Россия  
    Дата: 06.02.04 16:13
    Оценка:
    Попытка номер 3
    static MeyersSingleton &Instance()
        {
            static volatile MeyersSingleton* the_ton=NULL;   
            if (!the_ton) {  
               HANDLE h;
               h=CreateMutex(NULL, true, "mutext");
               static MeyersSingleton obj;
               the_ton=&obj;
               ReleaseMutex(h);
               CloseHandle(h);
            } 
            return *the_ton;
        }


    AS>И так медленно И неправильно.

    AS>2. объвлять его членом класса.
    Зачем?
    AS>4. Создание объекта для надежности в отдельную статическую функцию (дабы не искушать оптимизатор).
    Нечего ему тут оптимизровать.
    Да здравствует мыло душистое и веревка пушистая.
    Re: thread safe singlton - возможно ли такое в принципе
    От: PM  
    Дата: 09.02.04 08:39
    Оценка:
    Здраствуйте, Andrew S. Вы писали:

    AS> Всем доброго времени суток.

    AS> Итак, как было выяснено
    AS> здесь[/url<br />
    <span class='lineQuote level1'> AS&gt; ], синглтон Майерса не является потокобезопасным.</span><br />
    <br />
    []<br />
    Д. Шмидт рассматривал это в паттерне [url=http://www.cs.wustl.edu/~schmidt/PDF/DC-Locking.pdf]Double-Checked Locking
    Автор: Andrew S
    Дата: 06.02.04
    Posted via RSDN NNTP Server 1.7 "Bedlam"
    Re: Мой вариант. Работает ли это в принципе?
    От: Аноним  
    Дата: 21.06.04 08:02
    Оценка:
    Самому понадобилось: попробовал сделать сам.

    template <class T>
    class CSingleton
    {
        static T* pInstance;
        static CCriticalSection cs;
    
    protected:
        CSingleton();
        CSingleton(const CSingleton&);
        CSingleton& operator=(const CSingleton&);
        virtual ~CSingleton(){pInstance = NULL;}
    
    public:
        static T* Instance(void);
        void Free(void);
    }
    
    template <class T>
    T* CSingleton::pInstance = NULL;
    
    template <class T>
    T* CSingleton::Instance()
    {
        if(!pInstance)
        {
            cs.Lock();
    
            if(!pInstance)
            {
                pInstance = new T;
            }
    
            cs.Unlock();
        }
    }
    
    template <class T>
    void CSingleton::Free()
    {
        if(pInstance)
        {
            cs.Lock();
    
            if(pInstance)
            {
                delete this;
            }
            cs.Unlock();
        }
    }
    Re[2]: Мой вариант. Работает ли это в принципе?
    От: kmn Украина  
    Дата: 21.06.04 08:32
    Оценка:
    Здравствуйте, Аноним, Вы писали:

    А>Самому понадобилось: попробовал сделать сам.


    А>[ccode]

    А>template <class T>
    А>class CSingleton
    А>{
    А> static T* pInstance;
    А> static CCriticalSection cs;

    А>protected:

    А> CSingleton();
    А> CSingleton(const CSingleton&);
    А> CSingleton& operator=(const CSingleton&);
    А> virtual ~CSingleton(){pInstance = NULL;}

    А>public:

    А> static T* Instance(void);
    А> void Free(void);
    А>}

    Не дороговато ли хранить для каждого сингелтона свой объект синхронизации?
    Re[2]: Мой вариант. Работает ли это в принципе?
    От: Павел Кузнецов  
    Дата: 21.06.04 15:39
    Оценка:
    >
    > template <class T>
    > T* CSingleton::Instance()
    > {
    >     if(!pInstance)
    >     {
    >         cs.Lock();
    >         if(!pInstance)
    >             pInstance = new T;
    >         cs.Unlock();
    >     }
    > }
    >


    Это так называемый Double Checked Locking. В общем случае, без использования специфических для платформы средств для организации memory barrier, не работает. Немного подробнее: http://rsdn.ru/Forum/Message.aspx?mid=380025&amp;only=1
    Автор: Павел Кузнецов
    Дата: 10.09.03
    Posted via RSDN NNTP Server 1.9 beta
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[3]: Мой вариант. Работает ли это в принципе?
    От: Блудов Павел Россия  
    Дата: 22.06.04 03:28
    Оценка:
    Здравствуйте, kmn, Вы писали:

    kmn>Не дороговато ли хранить для каждого сингелтона свой объект синхронизации?


    Нет. Если singleton "легче" чем Critical Section — для него нет смысла
    делать отложенную инициализацию.
    ... << Rsdn@Home 1.1.4 beta 1 >>
    Re[3]: Мой вариант. Работает ли это в принципе?
    От: Аноним  
    Дата: 22.06.04 07:14
    Оценка:
    Здравствуйте, Павел Кузнецов, Вы писали:

    ПК>Это так называемый Double Checked Locking. В общем случае, без использования специфических для платформы средств для организации memory barrier, не работает. Немного подробнее: http://rsdn.ru/Forum/Message.aspx?mid=380025&amp;only=1
    Автор: Павел Кузнецов
    Дата: 10.09.03


    Как я понял из этой статьи надо сделать как-то так:

    template <class T>
    T* CSingleton<T>::Instance()
    {
        if(!pinstance_)
        {
            cs_.Lock();
    
            if(!pinstance_)
            {
                cs__.Lock();
                pinstance_ = new T;
                cs__.Unlock();
            }
    
            cs_.Unlock();
        }
    
        return pinstance_;
    }
    Re[4]: Мой вариант. Работает ли это в принципе?
    От: WolfHound  
    Дата: 22.06.04 09:39
    Оценка:
    Здравствуйте, <Аноним>, Вы писали:

    ПК>>Это так называемый Double Checked Locking. В общем случае, без использования специфических для платформы средств для организации memory barrier, не работает. Немного подробнее: http://rsdn.ru/Forum/Message.aspx?mid=380025&amp;only=1
    Автор: Павел Кузнецов
    Дата: 10.09.03


    Вот Double Checked Locking с memory barrier
    Re: thread safe singlton &mdash; возможно ли такое в принципе
    Автор: WolfHound
    Дата: 06.02.04

    Велосипед уже изобретен.
    ... << RSDN@Home 1.1.3 beta 1 >>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[2]: thread safe singlton - возможно ли такое в принципе
    От: bw  
    Дата: 22.06.04 10:57
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    WH>Здравствуйте, Andrew S, Вы писали:


    WH>Толком не тестировал но по идеи так

    <nice code skepped>

    Это же DCLP. Не на всех платформах будет работать. Хотя на IA-32 проблем конечно нет.
    Re[3]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 22.06.04 11:07
    Оценка:
    bw>Это же DCLP. Не на всех платформах будет работать. Хотя на IA-32 проблем конечно нет.

    Это не так. Обратите внимание на atom_get\atom_set
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[5]: Мой вариант. Работает ли это в принципе?
    От: Yacha Россия  
    Дата: 22.06.04 11:17
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    WH>Здравствуйте, <Аноним>, Вы писали:


    ПК>>>Это так называемый Double Checked Locking. В общем случае, без использования специфических для платформы средств для организации memory barrier, не работает. Немного подробнее: http://rsdn.ru/Forum/Message.aspx?mid=380025&amp;only=1
    Автор: Павел Кузнецов
    Дата: 10.09.03


    WH>Вот Double Checked Locking с memory barrier

    WH>Re: thread safe singlton &mdash; возможно ли такое в принципе
    Автор: WolfHound
    Дата: 06.02.04

    WH>Велосипед уже изобретен.
    А можно немножко прокоментировать код, на предмет, как здесь реализованы memory barrier-ы.
    В статье Скота Меерса, говорится о двух типах барьеров(aquire/release). http://www.nwcpp.org/Downloads/2004/DCLP_notes.pdf
    Re[4]: thread safe singlton - возможно ли такое в принципе
    От: bw  
    Дата: 22.06.04 11:22
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    bw>>Это же DCLP. Не на всех платформах будет работать. Хотя на IA-32 проблем конечно нет.


    AS>Это не так. Обратите внимание на atom_get\atom_set


    Видел. Их обоснованность вызвает у меня большие сомнения.
    Interlocked функции гарантируют атомарность конкретной операции над памятью, но не имеют никакого отношения к переупорядочиванию доступа к памяти. Именно в этом проблема DCLP. Например, мы можем получить в obj_ptr адрес недоконстурированного объекта.

    static T obj; //write 1: obj = <initialization value>
    ptr=&obj;
    atom_set((LONG*)&obj_ptr, (LONG)ptr); //write 2: obj_ptr = obj

    Эти операции записи могут быть переупорядочены и другой процессор увидит ненулевое значение в obj_ptr еще до того, как произойдет инициализация obj.
    Re[5]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 22.06.04 12:06
    Оценка:
    bw>Видел. Их обоснованность вызвает у меня большие сомнения.
    bw>Interlocked функции гарантируют атомарность конкретной операции над памятью, но не имеют никакого отношения к переупорядочиванию доступа к памяти. Именно в этом проблема DCLP. Например, мы можем получить в obj_ptr адрес недоконстурированного объекта.

    bw>static T obj; //write 1: obj = <initialization value>

    bw>ptr=&obj;
    bw>atom_set((LONG*)&obj_ptr, (LONG)ptr); //write 2: obj_ptr = obj

    bw>Эти операции записи могут быть переупорядочены и другой процессор увидит ненулевое значение в obj_ptr еще до того, как произойдет инициализация obj.


    На мой взгляд — это уже проблема самого объекта и компилятора. Если предполагается, что он будет использоваться таким образом (т.е. в MP среде), то вполне очевидно, что компилятор должен обеспечить валидность объекта (т.е. его полное конструирование) до первого обращения к объекту (либо взятия его адреса\ссылки). Иначе любая, даже однопоточная программа, будет постоянно иметь дело с необходимостью "ручной" синхронизации кешей процессоров.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[6]: thread safe singlton - возможно ли такое в принципе
    От: bw  
    Дата: 22.06.04 12:56
    Оценка:
    Здравствуйте, Andrew S, Вы писали:


    bw>>static T obj; //write 1: obj = <initialization value>

    bw>>ptr=&obj;
    bw>>atom_set((LONG*)&obj_ptr, (LONG)ptr); //write 2: obj_ptr = obj

    bw>>Эти операции записи могут быть переупорядочены и другой процессор увидит ненулевое значение в obj_ptr еще до того, как произойдет инициализация obj.


    AS>На мой взгляд — это уже проблема самого объекта и компилятора. Если предполагается, что он будет использоваться таким образом (т.е. в MP среде), то вполне очевидно, что компилятор должен обеспечить валидность объекта (т.е. его полное конструирование) до первого обращения к объекту (либо взятия его адреса\ссылки). Иначе любая, даже однопоточная программа, будет постоянно иметь дело с необходимостью "ручной" синхронизации кешей процессоров.


    Инициализация объекта для процессора по сути такая же операция записи, как и масса других. Если компилятор между всеми операциями записи будет вставлять барьер, то производительность загнется.

    Я думаю, тебя сбил с тольку термин "переупорядочивиание". Поясню: на одном процессоре мы выполняем приведенный выше код. Если этот процессор призведет write reoder, то другой процессор, выполняющий другой поток нашего процесса, может увидеть сначала результат второй операции, а потом результат первой. А вот наш первый процессор всегда будет видеть операции записи в правильном порядке, для него видимое поведение не изменится, будет ли write reoder или нет.

    PS. И насчет синхронизации кешей — это никогда не является проблемой программиста — это забота проектировщика железа. Как правильно заметили в параллельной ветке — "будь там хоть три кеша".
    Можно конечно для упрощения понимать проблему переупорядочивания, как проблему синхронизации кешей, но самом деле это не так.

    PPS. Насчtт DCLP можно почитать вот это http://www.nwcpp.org/Downloads/2004/DCLP_notes.pdf
    Только не дай Мейерсу ввести себя в заблуждения синхронизацией кешей . Мейерс ошибается. Нет такой проблемы.
    Re: thread safe singlton - возможно ли такое в принципе
    От: VVB16 Россия  
    Дата: 22.06.04 13:09
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    Часть реализации из ACE (по комментариям понятно, что используется):

    template <class TYPE, class ACE_LOCK> ACE_Singleton<TYPE, ACE_LOCK> *&
    ACE_Singleton<TYPE, ACE_LOCK>::instance_i (void)
    {
    #if defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES)
      // Pointer to the Singleton instance.  This works around a bug with
      // G++ and it's (mis-)handling of templates and statics...
      static ACE_Singleton<TYPE, ACE_LOCK> *singleton_ = 0;
    
      return singleton_;
    #else
      return ACE_Singleton<TYPE, ACE_LOCK>::singleton_;
    #endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */
    }
    
    template <class TYPE, class ACE_LOCK> TYPE *
    ACE_Singleton<TYPE, ACE_LOCK>::instance (void)
    {
      ACE_TRACE ("ACE_Singleton<TYPE, ACE_LOCK>::instance");
    
      ACE_Singleton<TYPE, ACE_LOCK> *&singleton =
        ACE_Singleton<TYPE, ACE_LOCK>::instance_i ();
    
      // Perform the Double-Check pattern...
      if (singleton == 0)
        {
          if (ACE_Object_Manager::starting_up () ||
              ACE_Object_Manager::shutting_down ())
            {
              // The program is still starting up, and therefore assumed
              // to be single threaded.  There's no need to double-check.
              // Or, the ACE_Object_Manager instance has been destroyed,
              // so the preallocated lock is not available.  Either way,
              // don't register for destruction with the
              // ACE_Object_Manager:  we'll have to leak this instance.
    
              ACE_NEW_RETURN (singleton, (ACE_Singleton<TYPE, ACE_LOCK>), 0);
            }
          else
            {
    #if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
              // Obtain a lock from the ACE_Object_Manager.  The pointer
              // is static, so we only obtain one per ACE_Singleton
              // instantiation.
              static ACE_LOCK *lock = 0;
              if (ACE_Object_Manager::get_singleton_lock (lock) != 0)
                // Failed to acquire the lock!
                return 0;
    
              ACE_GUARD_RETURN (ACE_LOCK, ace_mon, *lock, 0);
    
              if (singleton == 0)
                {
    #endif /* ACE_MT_SAFE */
                  ACE_NEW_RETURN (singleton, (ACE_Singleton<TYPE, ACE_LOCK>), 0);
    
                  // Register for destruction with ACE_Object_Manager.
                  ACE_Object_Manager::at_exit (singleton);
    #if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
                }
    #endif /* ACE_MT_SAFE */
            }
        }
    
      return &singleton->instance_;
    }


    Причем Lock тут может быть любой — thread_mutex (CriticalSection в Win) и т.п.
    Подробнее — в самом ACE.

    --
    Vitaly Belekhov
    Re[6]: thread safe singlton - возможно ли такое в принципе
    От: Павел Кузнецов  
    Дата: 22.06.04 13:43
    Оценка:
    > bw>Interlocked функции гарантируют атомарность конкретной операции над памятью, но не имеют никакого отношения к переупорядочиванию доступа к памяти.

    В соответствии с MSDN эти функции включают memory barrier на тех системах, где это нужно.

    > Именно в этом проблема DCLP. Например, мы можем получить в obj_ptr адрес недоконстурированного объекта.

    >
    > bw>static T obj; //write 1: obj = <initialization value>
    > bw>ptr=&obj;
    > bw>atom_set((LONG*)&obj_ptr, (LONG)ptr); //write 2: obj_ptr = obj
    >
    > bw>Эти операции записи могут быть переупорядочены и другой процессор увидит ненулевое значение в obj_ptr еще до того, как произойдет инициализация obj.
    >
    > На мой взгляд — это уже проблема самого объекта и компилятора. Если предполагается, что он будет использоваться таким образом (т.е. в MP среде), то вполне очевидно, что компилятор должен обеспечить валидность объекта (т.е. его полное конструирование) до первого обращения к объекту (либо взятия его адреса\ссылки).

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

    > Иначе любая, даже однопоточная программа, будет постоянно иметь дело с необходимостью "ручной" синхронизации кешей процессоров.


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

    Т.к. в данном случае memory barrier присутствует (в виде Interlocked*), все должно быть в порядке.
    Posted via RSDN NNTP Server 1.9 beta
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[7]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 22.06.04 14:56
    Оценка:
    ПК>Это не так: если запись переупорядочивает компилятор, то однопоточная программа будет получать значения не из памяти, а из регистров. Если же запись переупорядочивает процессор, то поток, выполняющийся на данном процессоре, будет получать значения из его кэша. Проблемы начнутся только при доступе к объекту из другого потока без внешней синхронизации.

    ПК>Т.к. в данном случае memory barrier присутствует (в виде Interlocked*), все должно быть в порядке.


    Да, но он присутствует относительное не самого объекта, а указателя на него. Если atom_get\atom_set гарантируют, что процессоры будут синхронизированы относительно общего состояния (т.е. синхронизация очередей команд, кеша и прочее) — тогда конечно. (насколько я помню, interlocked это гарантирует только для собственно указателя, точнее, для той области памяти, что представляет значение указателя. На самом деле он гарантирует, что, изменяя значение, мы корректно его изменим + получим обратно то, что было. Кстати, реализация atom_get ака WolfHound абсолюно бессмысленна — подробнее в Рихтере).
    Т.о. ситуация, описанная WB (т.е. когда мы осуществили атомарно изменение указателя, но не уведомили другие процессоры об инициализации T) вполне возможна.

    Вот из описания команды\сигнала lock

    Команда с захватом гарантированно захватывает только область памяти, определяемую операндом назначения, но может захватить и большую область памяти. Например, типовые конфигурации 8086 и 80286 захватывают все физическое адресное пространство.

    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[8]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 22.06.04 15:32
    Оценка:
    AS>Вот из описания команды\сигнала lock

    AS>

    AS>Команда с захватом гарантированно захватывает только область памяти, определяемую операндом назначения, но может захватить и большую область памяти. Например, типовые конфигурации 8086 и 80286 захватывают все физическое адресное пространство.


    Хотя, с другой стороны, из манула IA32:

    Locked operations are atomic with respect to all other memory operations and
    all externally visible events. Only instruction fetch and page table
    accesses can pass locked instructions. Locked instructions can be used to
    synchronize data written by one processor and read by another processor.

    For the P6 family processors, locked operations serialize all outstanding
    load and store operations (that is, wait for them to complete).
    This rule is
    also true for the Pentium 4 and Intel Xeon processors, with one exception:
    load operations that reference weakly ordered memory types (such as the WC
    memory type) may not be serialized.


    Из этого куска следует, что lock для семейства P6 наконец-то начинает работать как memory barrier (и в этом случае atom_get ака WolfHound будет работать). Великолепно, но как быть с P5 и 486-386?
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[7]: thread safe singlton - возможно ли такое в принципе
    От: bw  
    Дата: 22.06.04 17:11
    Оценка:
    Здравствуйте, Павел Кузнецов, Вы писали:

    >> bw>Interlocked функции гарантируют атомарность конкретной операции над памятью, но не имеют никакого отношения к переупорядочиванию доступа к памяти.


    ПК>В соответствии с MSDN эти функции включают memory barrier на тех системах, где это нужно.


    <skipped>

    ПК>Т.к. в данном случае memory barrier присутствует (в виде Interlocked*), все должно быть в порядке.


    Действительно, InterlockedExchange генерирует нужный mb — мой MSDN оказался староват
    Зачем это понадобилось MS не знаю. Наверное, чтобы старый плохой код продолжал работать...

    Однако, даже если отвлечься от того, что решение получилось WIN API-specific, хотя автор наверняка имел в виду общее решение, то и в этом случае решение нерабочее.

    Неправильно в нем то, что чтение тоже может быть переупорядочено.


        // код WoulfHound
        static T &Instance()
        {
            static T* obj_ptr=0;//Статическая инициализация(потокобезопасно)
            static LONG flag=0;//Аналогично
            T* ptr=(T*)atom_get((LONG*)&obj_ptr); //read 1
            if(!ptr)
            {
                auto_lock lock(&flag);
                ptr=(T*)atom_get((LONG*)&obj_ptr);
                if(!ptr)
                {
                    static T obj;//Создастся пи первом поподании сюда
                    ptr=&obj;
                    atom_set((LONG*)&obj_ptr, (LONG)ptr);
                }
            }
            return *ptr;
        }
        
        //код предполагаемого пользователя синглтона
        some_call(); //read 0
        T x = Instance();
        std::cout << x; //read 2



    В точке read_1 мы читаем значение указателя, в точке read_2 мы читаем данные по этому указателю.
    Эти две операции могут быть переупорядочены. Может возникнуть вопрос, как такое может случиться, если мы сначала читаем указатель, по которому затем уже читаем данные — может. Если каким-то образом предшествующий использованию синглтона some_call() произвел чтение read_0 из будущего адреса obj_ptr.

    На IA-64 такое невозможно — там есть соответствующий data-dependency restriction.
    На альфе возможно: http://www.cs.umd.edu/~pugh/java/memoryModel/AlphaReordering.html
    На SparcV9 кажется тоже возможно. Буду благодарен, если кто-нибудь сможет это подтвердить или опровергнуть.

    Чтобы проблемы не было надо ставить acquire lock после atom_get, а InterlockedExchangeAdd, через который реализован atom_get этого не делает.
    Re[10]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 22.06.04 17:15
    Оценка:
    >> но как быть с P5 и 486-386?

    ПК>Эти процессоры не переупорядочивают запись, так что им memory barrier не нужен, достаточно атомарности изменений.


    Верно, как то об этом не подумал. Тогда все ок, хотя фраза о том, что майкрософт гарантирует, что InterlockedXxxx для НЕ IA32 архитектур является memory barrier, все-таки настораживает...
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[8]: thread safe singlton - возможно ли такое в принципе
    От: Павел Кузнецов  
    Дата: 22.06.04 18:12
    Оценка:
    > чтение тоже может быть переупорядочено. <...> Чтобы проблемы не было надо ставить acquire lock после atom_get, а InterlockedExchangeAdd, через который реализован atom_get этого не делает.

    Если я правильно понял MSDN, то должен делать там, где это нужно...
    Posted via RSDN NNTP Server 1.9 beta
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[4]: Мой вариант. Работает ли это в принципе?
    От: Павел Кузнецов  
    Дата: 22.06.04 18:15
    Оценка:
    > ПК>Это так называемый Double Checked Locking. В общем случае, без использования специфических для платформы средств для организации memory barrier, не работает. Немного подробнее: http://rsdn.ru/Forum/Message.aspx?mid=380025&amp;only=1
    Автор: Павел Кузнецов
    Дата: 10.09.03

    >
    > Как я понял из этой статьи надо сделать как-то так:
    >
    >
    > template <class T>
    > T* CSingleton<T>::Instance()
    > {
    >     if(!pinstance_)
    >     {
    >         . . .
    >     }
    >
    >     return pinstance_;
    > }
    >


    Нет, этого недостаточно: перед чтением pinstance_ должен быть memory barrier, которого здесь нет.
    Posted via RSDN NNTP Server 1.9 beta
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[9]: thread safe singlton - возможно ли такое в принципе
    От: bw  
    Дата: 22.06.04 18:29
    Оценка:
    Здравствуйте, Павел Кузнецов, Вы писали:

    >> чтение тоже может быть переупорядочено. <...> Чтобы проблемы не было надо ставить acquire lock после atom_get, а InterlockedExchangeAdd, через который реализован atom_get этого не делает.


    ПК>Если я правильно понял MSDN, то должен делать там, где это нужно...


    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/interlockedexchange64.asp
    Вроде ни слова про барьеры.
    Re[10]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 22.06.04 18:30
    Оценка:
    ПК>>Если я правильно понял MSDN, то должен делать там, где это нужно...

    bw>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/interlockedexchange64.asp

    bw>Вроде ни слова про барьеры.

    А вы посмотрите код этих функций, и все станет понятно.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[3]: thread safe singlton - возможно ли такое в принципе
    От: Шахтер Интернет  
    Дата: 23.06.04 00:08
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    ПК>>Один из вариантов — инициализировать критическую секцию/мьютекс заведомо до

    ПК>>использования singleton.

    AS>Верно. Например, в файле реализации синглетона, как это сделано у Александреску.

    AS>Но тогда возможна ситуация вызова Instance с еще непроинициализированной критической секцией. В общем, за что боролись... Печально, Павел, неужели нет красивого выхода из этой ситауции?

    ПК>>Если структура программы настолько аморфна, что ничего о времени использования

    ПК>>тех или иных объектов сказать нельзя, возможно, стоит задуматься об архитектуре.
    AS>Нет, меня вполне устраивает объявление объекта синглтона в файле реализации и я могу гарантировать, что Instance будет вызываться только после инициализации статических объектов. Но меня интересует не конкретный проект, а именно принцип.

    Не могу понять. Если вы можете гарантировать, что Instance вызывается после входа в main, то какие проблемы с инициализацией критической секции? Никаких.
    Если же у вас Instance вызывется до входа в main, то это значит, что нет отложенной инициализации и нет проблем с многопоточностью -- и синглетон вам не нужен тогда, а нужно решить проблему порядка конструирования статических объектов -- но это уже совсем другая проблема.
    ... << RSDN@Home 1.1.0 stable >>
    В XXI век с CCore.
    Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
    Re[3]: thread safe singlton - возможно ли такое в принципе
    От: Шахтер Интернет  
    Дата: 23.06.04 00:28
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    ПК>>Один из вариантов — инициализировать критическую секцию/мьютекс заведомо до

    ПК>>использования singleton.

    AS>Верно. Например, в файле реализации синглетона, как это сделано у Александреску.

    AS>Но тогда возможна ситуация вызова Instance с еще непроинициализированной критической секцией. В общем, за что боролись... Печально, Павел, неужели нет красивого выхода из этой ситауции?

    Хотите хинт насчет критической секции? Есть критические секции с автоинициализацией. Т.е. для них не нужно вызывать конструктор -- достаточно статической инициализации членов структуры начальными значениями.
    ... << RSDN@Home 1.1.0 stable >>
    В XXI век с CCore.
    Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
    Re[4]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 23.06.04 07:22
    Оценка:
    ПК>>>Один из вариантов — инициализировать критическую секцию/мьютекс заведомо до
    ПК>>>использования singleton.

    AS>>Верно. Например, в файле реализации синглетона, как это сделано у Александреску.

    AS>>Но тогда возможна ситуация вызова Instance с еще непроинициализированной критической секцией. В общем, за что боролись... Печально, Павел, неужели нет красивого выхода из этой ситауции?

    Ш>Хотите хинт насчет критической секции? Есть критические секции с автоинициализацией. Т.е. для них не нужно вызывать конструктор -- достаточно статической инициализации членов структуры начальными значениями.


    Какой конструктор? Вы про что? Я про win32 критические секции
    А вообще — теме уже 300 лет, проблема (точнее, вопрос) давно решена...
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 23.06.04 07:31
    Оценка:
    ПК>>>Если структура программы настолько аморфна, что ничего о времени использования
    ПК>>>тех или иных объектов сказать нельзя, возможно, стоит задуматься об архитектуре.
    AS>>Нет, меня вполне устраивает объявление объекта синглтона в файле реализации и я могу гарантировать, что Instance будет вызываться только после инициализации статических объектов. Но меня интересует не конкретный проект, а именно принцип.

    Ш>Не могу понять. Если вы можете гарантировать, что Instance вызывается после входа в main, то какие проблемы с инициализацией критической секции? Никаких.

    Ш>Если же у вас Instance вызывется до входа в main, то это значит, что нет отложенной инициализации и нет проблем с многопоточностью -- и синглетон вам не нужен тогда, а нужно решить проблему порядка конструирования статических объектов -- но это уже совсем другая проблема.

    Вы не то выделяете

    AS>> Но меня интересует не конкретный проект, а именно принцип.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[11]: thread safe singlton - возможно ли такое в принципе
    От: bw  
    Дата: 23.06.04 14:41
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    ПК>>>Если я правильно понял MSDN, то должен делать там, где это нужно...


    bw>>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/interlockedexchange64.asp

    bw>>Вроде ни слова про барьеры.

    AS>А вы посмотрите код этих функций, и все станет понятно.


    Будет возможность — помотрю и напишу о результатах.

    Вполне возможно MS пошел на то,чтобы во всех Interlocked операциях добавить mb, хоть их и отговаривали
    http://groups.google.com/groups?hl=en&amp;lr=&amp;ie=UTF-8&amp;frame=right&amp;rnum=171&amp;thl=1022546285,1023289076,1023286257,1023283857,1023276945,1023275247,1022994050,1022953118,1022946105,1022718570,1022701862,1022362731&amp;seekm=3F78BD48.63529E65%40xemaps.com#link179


    Своей критикой предложенного синглтона, я просто хотел подчеркнуть, что сами по себе atomic-операции,
    имеющиеся практически на любом процессоре, ничего не гарантируют. Вдруг кто захочет спортировать
    этот синглетон не под Win — чтобы знали подводные камни
    Re: thread safe singlton - возможно ли такое в принципе
    От: Дарней Россия  
    Дата: 02.07.04 04:17
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Всем доброго времени суток.

    AS>Итак, как было выяснено здесь
    Автор: Andrew S
    Дата: 06.02.04
    , синглтон Майерса не является потокобезопасным.


    честно говоря, я чего-то не понимаю. А почему этот синглтон должен был быть безопасным? Вроде бы никаких оснований для этого нет
    Всех излечит, исцелит
    добрый Ctrl+Alt+Delete
    Re[2]: Вопрос.
    От: sergey_shandar США http://getboost.codeplex.com/
    Дата: 08.07.04 03:38
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    ...

    Можно ли этот код сократить до такого?

    WH>
    ...
    WH>    static T &Instance()
    WH>    {
    WH>        static T* obj_ptr=0;//Статическая инициализация(потокобезопасно)
    WH>        static LONG flag=0;//Аналогично
    WH>        auto_lock lock(&flag);
    WH>        ptr=(T*)atom_get((LONG*)&obj_ptr);
    WH>        if(!ptr)
    WH>        {
    WH>            static T obj;//Создастся пи первом поподании сюда
    WH>            ptr=&obj;
    WH>            atom_set((LONG*)&obj_ptr, (LONG)ptr);
    WH>        }
    WH>        return *ptr;
    WH>    }
    ...
    WH>


    Прежде всего, вопрос не о скорости, а о безопасности.
    getboost.codeplex.com
    citylizard.codeplex.com
    Re[3]: Вопрос.
    От: WolfHound  
    Дата: 08.07.04 15:49
    Оценка:
    Здравствуйте, sergey_shandar, Вы писали:

    _>Можно ли этот код сократить до такого?

    хъ
    _>Прежде всего, вопрос не о скорости, а о безопасности.
    Вроде можно. А нужно?
    ... << RSDN@Home 1.1.3 beta 1 >>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[2]: thread safe singlton - возможно ли такое в принципе
    От: Lexey Россия  
    Дата: 08.07.04 21:57
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    WH>struct auto_lock

    WH>{
    WH> auto_lock(LONG* ptr)
    WH> :ptr_(ptr)
    WH> {
    WH> while(atom_set(ptr_, 1))
    WH> Sleep(1);
    WH> }

    Тут недавно в boost.develop появилась забавная нитка, в которой один перец довольно убедительно утверждает, что спин-локи, вообще говоря, довольно хреновая вещь, если у них нет fallback'а на синхронизационные примитивы ОС (там шла дискуссия по поводу boost::lightweight_mutex).
    ... << RSDN@Home 1.1.4 beta 1 >>
    "Будь достоин победы" (c) 8th Wizard's rule.
    Re[4]: Вопрос.
    От: sergey_shandar США http://getboost.codeplex.com/
    Дата: 09.07.04 02:09
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    _>>Прежде всего, вопрос не о скорости, а о безопасности.

    WH>Вроде можно. А нужно?

    Спросил только для того что бы получше понять смысл написанного. Человек я простой, только простые вещи понимаю. Насколько я понимаю, все будет работать даже так:
    ...
    WH>    static T &Instance()
    WH>    {
    WH>        static LONG flag=0;
    WH>        auto_lock lock(&flag);
    WH>        static T obj;
    WH>        return obj;
    WH>    }
    ...

    Правильно?
    getboost.codeplex.com
    citylizard.codeplex.com
    Re[5]: Вопрос.
    От: WolfHound  
    Дата: 09.07.04 09:41
    Оценка:
    Здравствуйте, sergey_shandar, Вы писали:

    _>Спросил только для того что бы получше понять смысл написанного. Человек я простой, только простые вещи понимаю. Насколько я понимаю, все будет работать даже так:

    хъ
    _>Правильно?
    А вот тут нет memory barrier(он встроен в InterlockedXXX функции). Так что теоритически могут быть проблемы.
    ... << RSDN@Home 1.1.3 beta 1 >>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[3]: thread safe singlton - возможно ли такое в принципе
    От: WolfHound  
    Дата: 09.07.04 09:41
    Оценка:
    Здравствуйте, Lexey, Вы писали:

    L>Тут недавно в boost.develop появилась забавная нитка, в которой один перец довольно убедительно утверждает, что спин-локи, вообще говоря, довольно хреновая вещь, если у них нет fallback'а на синхронизационные примитивы ОС (там шла дискуссия по поводу boost::lightweight_mutex).

    А можно ее сюда процитировать?
    ... << RSDN@Home 1.1.3 beta 1 >>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[4]: thread safe singlton - возможно ли такое в принципе
    От: Lexey Россия  
    Дата: 09.07.04 21:54
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    L>>Тут недавно в boost.develop появилась забавная нитка, в которой один перец довольно убедительно утверждает, что спин-локи, вообще говоря, довольно хреновая вещь, если у них нет fallback'а на синхронизационные примитивы ОС (там шла дискуссия по поводу boost::lightweight_mutex).

    WH>А можно ее сюда процитировать?

    Если только в понедельник. Дома я ее не читаю, а подписываться ради этого лень.
    ... << RSDN@Home 1.1.4 beta 1 >>
    "Будь достоин победы" (c) 8th Wizard's rule.
    Re[5]: thread safe singlton - возможно ли такое в принципе
    От: Lexey Россия  
    Дата: 12.07.04 14:16
    Оценка:
    Здравствуйте, Lexey, Вы писали:

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


    L>>>Тут недавно в boost.develop появилась забавная нитка, в которой один перец довольно убедительно утверждает, что спин-локи, вообще говоря, довольно хреновая вещь, если у них нет fallback'а на синхронизационные примитивы ОС (там шла дискуссия по поводу boost::lightweight_mutex).

    WH>>А можно ее сюда процитировать?

    L>Если только в понедельник. Дома я ее не читаю, а подписываться ради этого лень.


    Ну держись, сейчас буду постить.

    I believe there is a mistake in the 'details/lwm_gcc.hpp' and 
    'details/lwm_linux.hpp' (and possibly the other lightweight_mutex 
    implementation as well -- I haven't looked at them).
     
    In both of these files we have a counter (m_.a_) that is initialized to 1.  
    The lock routine is implemented as follows:
     
    while( !__exchange_and_add(&m_.a_, -1) ){
      __atomic_add(&m_.a_, 1);
      sched_yield();
    }
     
    The unlock as:
    __atomic_add(&m_.a_, 1);
     
    This works if there are only two contenders for the lock.  It can fail if 
    there are three or more:
     
    1-  Thread one takes the lock, putting the counter at 0.
    2-  Thread two does the __exchange_and_add, fails the test, and then its time 
    time slice expires before the __atomic_add, leaving the counter at -1.
    3-  Thread three also takes the lock (because !-1 is false).
     
    A simple solution is to initialize the counter to zero and replace the above 
    lock by:
     
    while( __exchange_and_add(&m_.a_, 1) ){
      __atomic_add(&m_.a_, -1);
      sched_yield();
    }
     
    and the unlock by:
    __atomic_add(&m_.a_, -1);
     
    This would result in:
    1-  Thread one takes the lock, putting the counter at 1.
    2-  Thread two does the __exchange_and_add, fails the test, and then its time 
    slice expires before it can do the __atomic_add, leaving the counter at 2.
    3-  Thread cannot take the the lock (because 2 is true).
     
    - -T
     
    - -- 
     Tyson Whitehead  (-twhitehe@uwo.ca -- WSC-)
     Computer Engineer                        Dept. of Applied Mathematics,
     Graduate Student- Applied Mathematics    University of Western Ontario,
     GnuPG Key ID# 0x8A2AB5D8                 London, Ontario, Canada
    
    
    ---------------------------------------------------------------------------------------------------------------------
    
    Tyson Whitehead wrote:
    >  I believe there is a mistake in the 'details/lwm_gcc.hpp' and 
    'details/lwm_linux.hpp' (and possibly the other lightweight_mutex 
    implementation as well -- I haven't looked at them). 
    
     
    I am not sure what the status of these are.  Are other components
    supposed to be using these?  In addition to what you mentioned, they're
    broken in other ways:
     
    >  In both of these files we have a counter (m_.a_) that is initialized to 1.  
    The lock routine is implemented as follows:
    while( !__exchange_and_add(&m_.a_, -1) ){
      __atomic_add(&m_.a_, 1);
      sched_yield(); 
    
     
    If a low priority thread is preempted by a high priority thread
    immediately before __atomic_add, and the high priority thread is
    attempting to grab the spinlock, deadlock is acheived, despite the
    sched_yield().
     
    I think that spinlocks should not be used in a way other than as an
    optimization for the non-contended case in an algorithm with fallback to
    a real synchronization primative.  I think it is a bug to do otherwise
    on most non-realtime systems.
     
    Aaron W. LaFramboise
    
    -------------------------------------------------------------------------------------------------------------------------
    
    Aaron W. LaFramboise wrote:
    >  I am not sure what the status of these are.  Are other components
    supposed to be using these? 
    
     
    I came upon them when I was checking out the smart pointers implementation.  
    Grepping the source seems to indicate 'lightweight_mutex.hpp' is only used by  
    the smart pointers (only included by 'quick_allocator.hpp' and 
    'shared_count.hpp') under multithreaded conditions.
     
    >  In addition to what you mentioned, they're broken in other ways: 
    If a low priority thread is preempted by a high priority thread
    immediately before __atomic_add, and the high priority thread is
    attempting to grab the spinlock, deadlock is acheived, despite the
    sched_yield(). 
    
     
    I missed that one.  You're right though, and not only that, but the 
    sched_yield manpage states (I'm assuming this applies to threads -- threads 
    in Linux are actually processes -- right?):
     
    "Note: If the current process is the only process in the highest priority list 
    at that time, this process will continue to run after a  call to 
    sched_yield."
     
    The implementer seemed to be aware there could be priority problems though.  
    The relevant comments in 'lightweight_mutex.hpp' are:
     
    //  * Used by the smart pointer library
    //  * Performance oriented
    //  * Header-only implementation
    //  * Small memory footprint
    //  * Not a general purpose mutex, use boost::mutex, CRITICAL_SECTION or
    //    pthread_mutex instead.
    //  * Never spin in a tight lock/do-something/unlock loop, since
    //    lightweight_mutex does not guarantee fairness.
    //  * Never keep a lightweight_mutex locked for long periods.
    //
    //  The current implementation can use a pthread_mutex, a CRITICAL_SECTION,
    //  or a platform-specific spinlock.
    //
    //  You can force a particular implementation by defining
    //  BOOST_LWM_USE_PTHREADS,
    //  BOOST_LWM_USE_CRITICAL_SECTION, or 
    //  BOOST_LWM_USE_SPINLOCK.
    //
    //  If neither macro has been defined, the default is to use a spinlock on
    //  Win32, and a pthread_mutex otherwise.
    //
    //  Note that a spinlock is not a general synchronization primitive. In
    //  particular, it is not guaranteed to be a memory barrier, and it is
    //  possible to "livelock" if a lower-priority thread has acquired the
    //  spinlock but a higher-priority thread is spinning trying to acquire the
    //  same lock.
    //
    //  For these reasons, spinlocks have been disabled by default except on
    //  Windows, where a spinlock can be several orders of magnitude faster than a
    //  CRITICAL_SECTION.
     
    The current Win32 doesn't have the counter problems, and claims to be able to 
    yield to lower priority threads, so it should be okay.  The relevant lock 
    routine is (m_.l_ is initialized to 0):
     
    while( InterlockedExchange(&m_.l_, 1) ){
      // Note: changed to Sleep(1) from Sleep(0).
      // According to MSDN, Sleep(0) will never yield
      // to a lower-priority thread, whereas Sleep(1)
      // will. Performance seems not to be affected.
      Sleep(1);
    }
     
    The unlock routine is:
    InterlockedExchange(&m_.l_, 0);
     
    - -T
     
    - -- 
     Tyson Whitehead  (-twhitehe@uwo.ca -- WSC-)
     Computer Engineer                        Dept. of Applied Mathematics,
     Graduate Student- Applied Mathematics    University of Western Ontario,
     GnuPG Key ID# 0x8A2AB5D8                 London, Ontario, Canada
    
    -------------------------------------------------------------------------------------------
    
    Tyson Whitehead wrote:
    >  The current Win32 doesn't have the counter problems, and claims to be able to 
    yield to lower priority threads, so it should be okay.  The relevant lock 
    routine is (m_.l_ is initialized to 0):
    while( InterlockedExchange(&m_.l_, 1) ){
      // Note: changed to Sleep(1) from Sleep(0).
      // According to MSDN, Sleep(0) will never yield
      // to a lower-priority thread, whereas Sleep(1)
      // will. Performance seems not to be affected.
      Sleep(1);
    } 
    
     
    For what its worth, while it avoids deadlocking problems, this code is
    also wrong.
     
    Synchronization code should never sleep.  That code above will actually
    sleep for the minimum amount of time Windows allows, which is usually
    10ms.  I measured the performance of this spinlock a while back when
    improvements to GCC's Windows mutexes were being discussed on the MinGW
    lists, and in some cases where there is substanctial contention over
    short-lived locks, the performance degradation is quite unacceptable.
    Certain naïve benchmarks might not notice, though, because during the
    period waiters are sleeping, the lock will be accessable.
     
    I think the code above could lead to severe slowdowns in some usage
    cases, and could lead to difficult to diagnose intermittant 'blips' of
    bad performance in others.
     
    In any case, my point is that spinlocks are always going to be wrong in
    these sorts of situations unless coupled with some other primative.  In
    fact, spinning at all is usually the wrong thing to do.  On single CPU
    systems, it is always a waste of precious time.  On multi CPU systems,
    it can cause very undesirable memory bus slowdowns.
     
    The best general locking strategy I have seen--which is used by Linux
    futexes and GCC for Windows' new locks--is where a normal scheduler
    locking primative is wrapped by a quick userspace atomic operation to
    avoid locking in the noncontended case.  The downside is that, on
    Windows for example, this will require 8 bytes of storage.  I'm not sure
    how shared_ptr uses mutexes, but this might not be acceptable.
     
    These spinlocks need to be fixed.  Is anyone working on this?
     
    Aaron W. LaFramboise
    -------------------------------------------------------------------------------------
    
    Aaron,
     
    Before taking your word for it, I would like to hear more about how your
    benchmarks relate to smart pointers.
     
    It sounds reasonable that the kind of lock described will perform badly in
    high-contention situations. But what evidence do you have that there is any
    probability of high contention, especially when, as you say, the locks are
    short-lived? These locks aren't taken every time the smart pointer is accessed;
    they're only taken when a copy is made. So to get the high contention you speak
    of, you would have to have two threads repeatedly making copies of the "same"
    smart pointer. From where I stand, this seems sufficiently rare that the extra
    performance gain in the common cases is worth it.
     
    /Mattias
    -------------------------------------------------------------------------------------
    
    flodin@cs.umu.se wrote:
    >  It sounds reasonable that the kind of lock described will perform badly in
    high-contention situations. But what evidence do you have that there is any
    probability of high contention, especially when, as you say, the locks are
    short-lived? These locks aren't taken every time the smart pointer is accessed;
    they're only taken when a copy is made. So to get the high contention you speak
    of, you would have to have two threads repeatedly making copies of the "same"
    smart pointer. From where I stand, this seems sufficiently rare that the extra
    performance gain in the common cases is worth it. 
    
     
    [these comments are specific to the win32 spinlock discussed]
     
    I have two specific concerns.
     
    1) Personally, I value predictable performance.  I would prefer slight
    performance degradation (Note, however, that I am not examining the
    actual numbers.) to the case where I may have an occasional very long
    wait.  (Specific example: If a graphically intensive program is aiming
    for 30 frames per second, that is only about 30ms per frame.  It would
    be very unfortunate if, even occasionally, a single smart pointer copy
    accounted for 1/3 of the time it took to render a frame.)
     
    2) In "thundering herd" situations, contention is unavoidable, and
    performance may be paramount.  The possibility of a single thread
    halting many other threads for 10ms on a machine with many processors is
    disturbing. (Specific example: In a case where thread is producing work
    for many consumer threads on a multiprocessor machine, and obtaining the
    work involves copying a smart pointer, it is possible that some amount
    of threads will forced to sleep every single time, which might be a
    substantial percentage of total job wall clock time.)
     
    In any case, I feel fairly strongly that sleeping is not the right thing
    to do.  Despite the weakness in appeal to authority, I will note that I
    have seen Butenhof make the same assertion on Usenet, surely in a manner
    more eloquent than mine.
     
    I previously neglected to suggest alternatives.
     
    1) A generally sound 8-byte mutex could be used.  I am not sure how bad
    this would be in terms of storage efficiency.  It may be possible to
    implement it using less storage, but I have no specific information on this.
     
    2) I've seen a shared_ptr count implementation that used
    InterlockedIncrement instead of the lwm code.  I have not examined this
    in detail; however it seems that an approach like this is better in all
    respects than trying to manage locks if the only need is to maintain a
    count (which is what many mutex primatives are doing anyway).  Is there
    some reason this cannot be used?
     
    What do you think?
     
    Aaron W. LaFramboise
    --------------------------------------------------------------------------------



    и т.д. Как потом выяснилось, насчет 10 ms, он все-таки загнул. Но народ вроде сошелся на том, что критичексая секция все-таки получше будет.
    "Будь достоин победы" (c) 8th Wizard's rule.
    Re[6]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 12.07.04 15:01
    Оценка:
    L>и т.д. Как потом выяснилось, насчет 10 ms, он все-таки загнул. Но народ вроде сошелся на том, что критичексая секция все-таки получше будет.
    Естественно, любой практически системный сервис, предоставляемый OS будет лучше (ну или _должен_ быть лучше). Но..
    Каким образом Вы сможете использовать критическую секцию в приведенном синглетоне? Ее надо сначала проинициализировать — pkunzip.zip получается. Это во-первых. А во-вторых — производительность auto_lock нас не волнует, поскольку используется двойная проверка с memory barrier — т.о. в блок с auto_lock мы будем попадать только на этапе инициализации объекта синглтона, да и то скорее всего один раз. Единственная альтернатива (критические секции и неименованные мутексы не подойдут по приведенным выше соображениям) — это именованый мутекс. Но я сильно сомневаюсь, что поиск объекта по имени работает достаточно быстро (настолько быстро, чтобы быть существенно быстрее представленной реализации). В общем, в данном применении это наиболее оптимальный вариант lightweight мутекса, наверное. К тому же не засоряется пространство имен объектов.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[7]: thread safe singlton - возможно ли такое в принципе
    От: Lexey Россия  
    Дата: 12.07.04 20:31
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    L>>и т.д. Как потом выяснилось, насчет 10 ms, он все-таки загнул. Но народ вроде сошелся на том, что критичексая секция все-таки получше будет.

    AS>Естественно, любой практически системный сервис, предоставляемый OS будет лучше (ну или _должен_ быть лучше). Но..
    AS>Каким образом Вы сможете использовать критическую секцию в приведенном синглетоне? Ее надо сначала проинициализировать — pkunzip.zip получается. Это
    AS> во-первых. А во-вторых — производительность auto_lock нас не волнует, поскольку используется двойная проверка с memory barrier — т.о. в блок с auto_lock мы будем попадать только на этапе инициализации объекта синглтона, да и то скорее всего один раз. Единственная альтернатива (критические секции и неименованные мутексы не подойдут по приведенным выше соображениям) — это именованый мутекс. Но я сильно сомневаюсь, что поиск объекта по имени работает достаточно быстро (настолько быстро, чтобы быть существенно быстрее представленной реализации). В общем, в данном применении это наиболее оптимальный вариант lightweight мутекса, наверное. К тому же не засоряется пространство имен объектов.

    В общем, я это и так знаю. И именованный мьютекс будет в подавляющем числе случаев будет существенно медленнее spin lock'a. Но, речь о том, что наверное самым правльным решением тут будет сочетание обоих приемов — spin lock с ограничением числа прокруток и без sleep'а + именованный мьютекс.
    ... << RSDN@Home 1.1.4 beta 1 >>
    "Будь достоин победы" (c) 8th Wizard's rule.
    Re[8]: thread safe singlton - возможно ли такое в принципе
    От: WolfHound  
    Дата: 13.07.04 08:41
    Оценка:
    Здравствуйте, Lexey, Вы писали:

    L>В общем, я это и так знаю. И именованный мьютекс будет в подавляющем числе случаев будет существенно медленнее spin lock'a. Но, речь о том, что наверное самым правльным решением тут будет сочетание обоих приемов — spin lock с ограничением числа прокруток и без sleep'а + именованный мьютекс.

    А в чем понт в спинлоке без слипа на однопроцессорной машине?
    ... << RSDN@Home 1.1.3 beta 1 >>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[9]: thread safe singlton - возможно ли такое в принципе
    От: Lexey Россия  
    Дата: 13.07.04 21:21
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    L>>В общем, я это и так знаю. И именованный мьютекс будет в подавляющем числе случаев будет существенно медленнее spin lock'a. Но, речь о том, что наверное самым правльным решением тут будет сочетание обоих приемов — spin lock с ограничением числа прокруток и без sleep'а + именованный мьютекс.

    WH> А в чем понт в спинлоке без слипа на однопроцессорной машине?

    Хм, а в чем понт слипа на однопроцессорной машине? Я вот не могу себе представить, зачем он в этом случае может быть нужен. Если происходит context switch, а lock все еще не отпущен другим потоком, то какой смысл делать слип, если можно сразу делать kernel wait? По хорошему, на однопроцессорной машине спин-лок вообще не нужен (критическая секция, кстати, его и игнорирует на однопроцессорных машинах).
    ... << RSDN@Home 1.1.4 beta 1 >>
    "Будь достоин победы" (c) 8th Wizard's rule.
    Re[10]: thread safe singlton - возможно ли такое в принципе
    От: WolfHound  
    Дата: 14.07.04 05:18
    Оценка:
    Здравствуйте, Lexey, Вы писали:

    L>Хм, а в чем понт слипа на однопроцессорной машине? Я вот не могу себе представить, зачем он в этом случае может быть нужен. Если происходит context switch, а lock все еще не отпущен другим потоком, то какой смысл делать слип, если можно сразу делать kernel wait? По хорошему, на однопроцессорной машине спин-лок вообще не нужен (критическая секция, кстати, его и игнорирует на однопроцессорных машинах).

    Быть может я чего не понимаю но если будет так:
    поток 1 начал создавать объект и случилось переключение контекста
    поток 2 захотел получить доступ к объекту но объект все еще залочен в этом случае Sleep форсирует переключение контекста
    или я чего не понял?
    ... << RSDN@Home 1.1.3 beta 1 >>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[11]: thread safe singlton - возможно ли такое в принципе
    От: Lexey Россия  
    Дата: 14.07.04 20:03
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    L>>Хм, а в чем понт слипа на однопроцессорной машине? Я вот не могу себе представить, зачем он в этом случае может быть нужен. Если происходит context switch, а lock все еще не отпущен другим потоком, то какой смысл делать слип, если можно сразу делать kernel wait? По хорошему, на однопроцессорной машине спин-лок вообще не нужен (критическая секция, кстати, его и игнорирует на однопроцессорных машинах).

    WH>Быть может я чего не понимаю но если будет так:
    WH>поток 1 начал создавать объект и случилось переключение контекста
    WH>поток 2 захотел получить доступ к объекту но объект все еще залочен в этом случае Sleep форсирует переключение контекста
    WH>или я чего не понял?

    Все так, только какой смысл тут делать sleep, если можно сразу в kernel wait уйти.
    ... << RSDN@Home 1.1.4 beta 1 >>
    "Будь достоин победы" (c) 8th Wizard's rule.
    Re[12]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 14.07.04 20:08
    Оценка:
    L>Все так, только какой смысл тут делать sleep, если можно сразу в kernel wait уйти.
    Пример кода приведите, который в kernel wait уходит?

    Вам тут надо переключить конекст (т.е. усыпить тред до следующего shedule) — в виндовс это делается при помощи Sleep.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[13]: thread safe singlton - возможно ли такое в принципе
    От: Lexey Россия  
    Дата: 15.07.04 20:42
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    L>>Все так, только какой смысл тут делать sleep, если можно сразу в kernel wait уйти.

    AS>Пример кода приведите, который в kernel wait уходит?

    Создание именованного ивента + Wait на нем.

    AS>Вам тут надо переключить конекст (т.е. усыпить тред до следующего shedule) — в виндовс это делается при помощи Sleep.


    Wait как раз и вызовет переключение контекста.
    ... << RSDN@Home 1.1.4 beta 1 >>
    "Будь достоин победы" (c) 8th Wizard's rule.
    Re[14]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 15.07.04 22:16
    Оценка:
    L>>>Все так, только какой смысл тут делать sleep, если можно сразу в kernel wait уйти.
    AS>>Пример кода приведите, который в kernel wait уходит?

    L>Создание именованного ивента + Wait на нем.


    Вообще то тут мы от этого пытаемся избавиться Посмотрите внимательно код синлтона с двойной проверкой. Сначала идет "грубая" быстрая проверка, просто на interlocked. Далее может идти все что угодно, что обеспечит мемори барриер до и после конструирования объекта и серийность входа.

    AS>>Вам тут надо переключить конекст (т.е. усыпить тред до следующего shedule) — в виндовс это делается при помощи Sleep.


    L>Wait как раз и вызовет переключение контекста.


    Sleep(1) тоже. А если слипа не будет — то тред, попавший в цикл по interlocked, не будет отдавать время и соотв, будет потреблять все процессорное время. Думаю, пользователям (да и инициализирующемуся в это время объекту синглтона) это не очень понравится А особенно не понравится тем, кто будет выполнять сей код на win98, где тред, крутящийся в таком цикле, очень хорошо затормозит систему и растянет процесс инициализации объекта синглтона в другом треде на ооооочень продолжительное время.

    И, еще раз — приведенный код (с auto_lock) будет вызываться от силы раз-два, и то при первом обращении к синглтону. Смысл создавать именованый kernel объект и засорять тем самым пространство имен? В общем, повторюсь, предложенный вариант будет вполне корректно работать на win32 (и, вероятно, с yield вместо sleep на linux — тут я не уверен, и прочитка топика, который привели вы, выяснила только одну проблему — что в линксовской используется счетчик (__atomic_add), а не просто обмен значениями, как в реализации, приведенной для win32 WolfHound'ом. Но это уже проблемы ДНК тех, кто писал эту реализацию, по моему глубокому убеждению. I love gnu libs code
    В общем — главный плюс этого кода не то, что он быстрее или медленнее нативных именованых объектов, предоставляемых ОС, а то, что он их собственно не требует, позволяя не засорять пространство имен на одноразовое фактически использование.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[15]: thread safe singlton - возможно ли такое в принципе
    От: Lexey Россия  
    Дата: 17.07.04 18:28
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    L>>>>Все так, только какой смысл тут делать sleep, если можно сразу в kernel wait уйти.

    AS>>>Пример кода приведите, который в kernel wait уходит?

    L>>Создание именованного ивента + Wait на нем.


    AS>Вообще то тут мы от этого пытаемся избавиться Посмотрите внимательно код синлтона с двойной проверкой. Сначала идет "грубая" быстрая проверка, просто на


    Я его в общем-то вполне нормально смотрел.

    AS> interlocked. Далее может идти все что угодно, что обеспечит мемори барриер до и после конструирования объекта и серийность входа.


    А я и не предлагаю убирать interlock и двойную, я предлагаю заменить спин-лок на kernel wait.

    AS>>>Вам тут надо переключить конекст (т.е. усыпить тред до следующего shedule) — в виндовс это делается при помощи Sleep.


    L>>Wait как раз и вызовет переключение контекста.


    AS>Sleep(1) тоже. А если слипа не будет — то тред, попавший в цикл по interlocked, не будет отдавать время и соотв, будет потреблять все процессорное время. Думаю, пользователям (да и инициализирующемуся в это время объекту синглтона) это не очень понравится А особенно не понравится тем, кто будет выполнять сей код на win98, где тред, крутящийся в таком цикле, очень хорошо затормозит систему и растянет процесс инициализации объекта синглтона в другом треде на ооооочень продолжительное время.


    А я где-то предполагал другое?

    AS>И, еще раз — приведенный код (с auto_lock) будет вызываться от силы раз-два, и то при первом обращении к синглтону. Смысл создавать именованый kernel объект и


    Далеко не факт. Если синглтон долго инициализируется, то вызываться он может много раз.

    AS> засорять тем самым пространство имен? В общем, повторюсь, предложенный вариант


    Ты боишься засорить пространство имен одним именованным ивентом? Это как-то совсем несерьезно звучит.

    AS> будет вполне корректно работать на win32 (и, вероятно, с yield вместо sleep на linux — тут я не уверен, и прочитка топика, который привели вы, выяснила только одну проблему — что в линксовской используется счетчик (__atomic_add), а не просто обмен значениями, как в реализации, приведенной для win32 WolfHound'ом. Но это уже проблемы ДНК тех, кто писал эту реализацию, по моему глубокому убеждению. I love


    В таком случае проблемы в ДНК есть у всех программистов.

    AS> gnu libs code


    В общем-то, этот топик кроме всего прочего обсуждал как раз вредность чистых спин-локов. Именно эту идею я и пытаюсь отстаивать. Кстати, я не привел конец этой дискуссии, так вот там народ сошелся на том, что lightweight_mutex пригоден только для очень коротких операций. В остальных случаях его лучше не использовать. Ты можешь гарантировать, что инициализация синглетона — быстрый процесс?

    AS> В общем — главный плюс этого кода не то, что он быстрее или медленнее нативных именованых объектов, предоставляемых ОС, а то, что он их собственно не требует, позволяя не засорять пространство имен на одноразовое фактически использование.


    Это как раз совершенно не серьезное преимущество.
    В общем, я могу предложить вариант, который наверное устроит и тебя и меня.
    Сделать синглетон-критическую секцию, создание которой защитить lightweight_mutex'ом (создание тут быстрое, так что можно). И вот эту критическую секцию и использовать при инициализации остальных синглетонов.
    ... << RSDN@Home 1.1.4 beta 1 >>
    "Будь достоин победы" (c) 8th Wizard's rule.
    Re[16]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 19.07.04 08:38
    Оценка:
    L>Это как раз совершенно не серьезное преимущество.
    L>В общем, я могу предложить вариант, который наверное устроит и тебя и меня.
    L>Сделать синглетон-критическую секцию, создание которой защитить lightweight_mutex'ом (создание тут быстрое, так что можно). И вот эту критическую секцию и использовать при инициализации остальных синглетонов.

    Одну критическую секция на все? Несерьезно, тормоза будут дикие, более того может быть так, что создание одного синглтона зависит от другого, и это происходит в разных потоках. Придется все-равно по одному именованному объекту на синглтон. Мне кажется, это не очень хорошая мысль. А точнее, очень _не_ хорошая. Впрочем, каждому свое
    В любом случае, серебряной пули не существует...
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[18]: thread safe singlton - возможно ли такое в принципе
    От: WolfHound  
    Дата: 21.07.04 18:50
    Оценка:
    Здравствуйте, Lexey, Вы писали:

    AS>>Одну критическую секция на все? Несерьезно, тормоза будут дикие, более того может

    L>Совсем не обязательно. Можно, например, сделать шаблонную "фабрику" критических секций.
    Гм??? А можно подробней?
    ... << RSDN@Home 1.1.3 beta 1 >>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[19]: thread safe singlton - возможно ли такое в принципе
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 21.07.04 21:12
    Оценка:
    AS>>>Одну критическую секция на все? Несерьезно, тормоза будут дикие, более того может
    L>>Совсем не обязательно. Можно, например, сделать шаблонную "фабрику" критических секций.
    WH>Гм??? А можно подробней?

    Как я понял, предлагается сделать синглтон (точнее, даже, фабрику), производящую объекты — критические секции По одной на каждый шаблонный класс синглтона. А уже ими пользоваться во второй проверке вместо авто лока (т.е. при захвате объека критической секции эта фабрика будет, защищаясь авто локом, в случае необходимости инициализировать критическую секцию — поскольку это быстро). Т.о. проблема частично решена введением дополнительного уровня абстракции. Остается дождаться, что кто-нибудь захочет поломать голову и найти баги в этой мысли — тогда придется вводить еще один уровень абстракции — фабрику фабрик критических секций и т.п.
    Немного пояснений.
    Как я понял — основные претензии к реализации авто лока у Lexey — это то, что "защищенный им код должен выполняться очень непродолжительное время". Это мягко говоря не так в случае win32 — там все вполне пристойно. А вот в линукс реализации используется декремент\инкремент при каждой "прокрутке", т.е. операция захвата выполняется не атомарно.
    while( __exchange_and_add(&m_.a_, 1) ){
    //  если в этот момент другой тред будет пытаться захватить автолок, наверняка будет бяка
      __atomic_add(&m_.a_, -1);
    //  и в этот наверняка тоже :)
      sched_yield();
    }

    Но повторюсь, это конкретная реализация. Я, к сожалению, не знаю линукс настолько, чтобы судить о возможности там сделать по-другому (т.е. не инкрементом, а обменом), но, очевидно, операция установки флага "занятости" автолока должна быть атомарной, ни в первом, ни во втором
    while( __exchange_and_add(&m_.a_, 1) ){
      __atomic_add(&m_.a_, -1);
      sched_yield();
    }

    (тут, правда, я смог придумать только вариант с MAX_UINT — 1 тредов, одновременно захватывающих автолок) приведенном варианте это не соблюдено.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.