Змінюй хід війни! Допомагай ЗСУ!

Safe singleton in C+ 03 - Разминка для мозга

🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #21
да нихера не подходит, не важно какой объект ты для синхронизации используешь, если ты его объявил статиком - это уже не рабочий вариант, т.к. статик переменная в момент обращения к ней из метода Instance может быть еще не инициализирована.

Схуяли? Если Instance - статик, а он обязан быть статик - то все будет хорошо.

При использовании именованного мьютекса, можно обойтись без статика, создавать мьютекс по имени прямо внутри метода Instance(). Таким образом мы не используем статик, а синхронизацию выполняет система.

Согласен.
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #22
Схуяли? Если Instance - статик, а он обязан быть статик - то все будет хорошо.

потому что кроме статика с объектом синхронизации класса MySinglton, в программе может быть еще масса других статик переменных. Инициализируются они все до main(). А теперь представь что будет, если до того как инициализируется MySingleton::s_syncRoot, произойдет инициализация другой статической переменной, которая во время инициализации обратится к MySingleton::Instance()?
А будет то что при вызове Instance() переменная MySingleton::s_syncRoot окажется еще не инициализированной, поэтому попытка использовать ее для синхронизации закончится крешем.
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #23
потому что кроме статика с объектом синхронизации класса MySinglton, в программе может быть еще масса других статик переменных. Инициализируются они все до main(). А теперь представь что будет, если до того как инициализируется MySingleton::s_syncRoot, произойдет инициализация другой статической переменной, которая во время инициализации обратится к MySingleton::Instance()?
А будет то что при вызове Instance() переменная MySingleton::s_syncRoot окажется еще не инициализированной, поэтому попытка использовать ее для синхронизации закончится крешем.

Дизайн значит хуевый если код полагается на порядок инициализации статиков. Не должно быть такой русской рулетки.
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #24
Дизайн значит хуевый если код полагается на порядок инициализации статиков. Не должно быть такой русской рулетки.

ну так в этом задача ТС-а и заключается - избавиться от этой русской рулетки. Есть идеи как сделать дизайн синглтона безопасным в этом отношении, без использования системных мьютексов?
Ведь порядок вызова статических инитиалайзеров не гарантирован компилятором.
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #25
ну так в этом задача ТС-а и заключается - избавиться от этой русской рулетки. Есть идеи как сделать дизайн синглтона безопасным в этом отношении, без использования системных мьютексов?
Ведь порядок вызова статических инитиалайзеров не гарантирован компилятором.

Ну там прагмы завсегда есть. Но это пиздос еще тот.

Чтоб избавиться от русской рулетки - надо дизайнить нормально, а не костыли для одноглазых потом изобретать.
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #26
Ну там прагмы завсегда есть. Но это пиздос еще тот.

Чтоб избавиться от русской рулетки - надо дизайнить нормально, а не костыли для одноглазых потом изобретать.

оно-то понятно, только в жизни редко так бывает чтобы дали денег все передизайнить, поэтому приходится решать проблемы в том что есть... :)

Кстати volatile в С++ не обспечивает атомарность, поэтому полагаться на него в многопоточной среде в корне неправильно.
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #27
оно-то понятно, только в жизни редко так бывает чтобы дали денег все передизайнить, поэтому приходится решать проблемы в том что есть... :)

Тогда прагмы, как уж совсем все плохо. Опять же, пофиксить статику надо один раз, чем ебаться с гонками в потоках если локи не юзать.

Кстати volatile в С++ не обспечивает атомарность, поэтому полагаться на него в многопоточной среде в корне неправильно.

Причем тут атомарность? volatile совсем не для того, а чтобы компилятор не умничал.



Я так понимаю, лугал написал какую-то хуйню и теперь хочет нашей помощи чтоб его зарплаты не лишили :)
Ибо вопрос реально слишком простой чтобы
а) без помощи гугла не разобраться самому
б) не сделать тупо в лоб с именоваными мутехами.
с) в стартпосле не писать код заведомо нихуя вообще не синглетона, а какой-то неведомой хуйни
д) все-таки погуглить немного
 
Останнє редагування:
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #28
Я так понимаю, лугал написал какую-то хуйню и теперь хочет нашей помощи чтоб его зарплаты не лишили :)
Ты как всегда все неправильно понимешь :)
Задача к моей работе не имеет никакого отношения, мне ее рассказли недавно, и я как человек любознательный и професиональный вот все пытаюсь найти решение.
Полная постоновка задачи, если тебе интересно звучит так:
В разрабатываемой коммерческой библиотеки сделать базовый класс синглтон, требующий минимального дополнительного кода, для превращения любого класса, который его наследует в синглтон.
Синглтон должен быть потоко и контекстно безопасен.

Ибо вопрос реально слишком простой чтобы
а) без помощи гугла не разобраться самому
б) не сделать тупо в лоб с именоваными мутехами.
Я рассматривал различные варианты, в том числе и с именованным мьютексом.
В случае с именнованным мьютексом непонятно кто должен закрывать хендлы, это раз. Два - дорого по времени.

с) в стартпосле не писать код заведомо нихуя вообще не синглетона, а какой-то неведомой хуйни
Вообщето код из старт поста это есть искомый синглетон в С++ 11, так как стандартом языка в данном случае гарантируеться полностью потокобезопасная инициализация статистеской внутренней переменной в момент первого вызова функции.
д) все-таки погуглить немного
Так в гугли хоть много хоть немного особо данный кейс и не решен. DCL эфективен в многопоточности, но с глобал скопом проблемы, из за инициализации объекта синхронизации.
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #29
Полная постоновка задачи, если тебе интересно звучит так:
В разрабатываемой коммерческой библиотеки сделать базовый класс синглтон, требующий минимального дополнительного кода, для превращения любого класса, который его наследует в синглтон.
Синглтон должен быть потоко и контекстно безопасен.

Ну допустим.

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

Враппер хендла его замечательно закроет при выходе из области видимости. Что дорого - то да. Но тебе или шашечки или ехать? В SMP и твоем древнем плюсе других простых вариантов нет.

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

Пиздец, ты совсем валера что-ли. Глянь на свой код _внимательно_. Какого хера Instance не статическая? :іржач:

Так в гугли хоть много хоть немного особо данный кейс и не решен. DCL эфективен в многопоточности, но с глобал скопом проблемы, из за инициализации объекта синхронизации.

С SMP будут проблемы так или иначе. А проблемы с глобал скопом надо решать не припарками для мертвых, а глобально. Что есть означает - не инициализировать синглетоны в статике.
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #30
Так. Объясните мне, дураку, почему, например, такая конструкция не будет удовлетворять условиям?

Код:
class Singleton
{
    static Singleton* volatile _instance;

protected:

..........................

public:

..........................

    static Singleton* Instance()
    {
        static LONG volatile lock = 0;
        if (!_instance)
        {
            if (!InterlockedCompareExchange(&lock, 1, 0))
            {
                _instance = new Singleton();
            }
            else
            {
                while (!_instance)
                {
                    Sleep(0);
                }
            }
        }
        return _instance;
    }

..........................
};

Это просто пример реализации.
 
Останнє редагування:
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #31
Так. Объясните мне, дураку, почему, например, такая конструкция не будет удовлетворять условиям?

Код:
class Singleton
{
    static Singleton* volatile _instance;

protected:

..........................

public:

..........................

    static Singleton* Instance()
    {
        static LONG volatile lock = 0;
        if (!_instance)
        {
            if (!InterlockedCompareExchange(&lock, 1, 0))
            {
                _instance = new Singleton();
            }
            else
            {
                while (!_instance)
                {
                    Sleep(0);
                }
            }
        }
        return _instance;
    }

..........................
};

Это просто пример реализации.

Да легко. теоретически с момента интелока до момента создания - другой поток может успеть тот же путь пройти.
Интерлок лочит только переменную, а не кусок кода.
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #32
Да легко. теоретически с момента интелока до момента создания - другой поток может успеть тот же путь пройти.
Интерлок лочит только переменную, а не кусок кода.

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

Другое дело, что значение _instance должно быть инициализировано видом:

Singleton* Singleton::_instance(NULL);

И вот тут лично у меня вопрос: эта инициализация относится к этапу инициализации константных объектов или этапу инициализации статических и глобальных переменных.
Если к этапу константных, то всё будет хорошо, а вот нет, то в теории мы можем заиметь рандомный ненулевой адрес указателя, что провалит все тесты. Но, о чудо, в такой ситуации мы можем проверять не _instance на ноль, а lock на ноль (точнее не на ноль, а на... два :), но это уже детали).
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #33
Интерлок лочит шину памяти, так что другой поток этот путь при всём желании не успеет пройти. Плюс мемори барьер, как бонус для мультипроцессорности.

Лочит на момент compare exchange. И все. На этом лок заканчивается.

Другое дело, что значение _instance должно быть инициализировано видом:

Singleton* Singleton::_instance(NULL);

И вот тут лично у меня вопрос: эта инициализация относится к этапу инициализации константных объектов или этапу инициализации статических и глобальных переменных.
Если к этапу константных, то всё будет хорошо, а вот нет, то в теории мы можем заиметь рандомный ненулевой адрес указателя, что провалит все тесты. Но, о чудо, в такой ситуации мы можем проверять не _instance на ноль, а lock на ноль (точнее не на ноль, а на... два :), но это уже детали).

Этап второй. Лок проверять не выйдет, он не гарантирует _instance ничего.
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #34
Лочит на момент compare exchange. И все. На этом лок заканчивается.

Ну так больше и не надо.
В худшем случае при переключении контекста после выполнения интерлок-инструкции первым потоком, второй поток будет стоять перед выполнением интерлок-инструкции, которую он успешно провалит и перейдёт в цикл со слипом.

Этап второй. Лок проверять не выйдет, он не гарантирует _instance ничего.

Проверка лок гарантирует, что при состоянии:

a) lock = 0, _instance не инициализирован, блокировка не выполнена.
b) lock = 1, _instance не инициализирован, блокировка выполняется.
c) lock = 2, _instance инициализирован.

Код написать?)
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #35
Ну так больше и не надо.
В худшем случае при переключении контекста после выполнения интерлок-инструкции первым потоком, второй поток будет стоять перед выполнением интерлок-инструкции, которую он успешно провалит и перейдёт в цикл со слипом.

Видимо ты прав.

Проверка лок гарантирует, что при состоянии:

a) lock = 0, _instance не инициализирован, блокировка не выполнена.
b) lock = 1, _instance не инициализирован, блокировка выполняется.
c) lock = 2, _instance инициализирован.

Код написать?)

А покажи, а то я что-то туплю.
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #36

Я на самом деле тоже теоритезирую, потомушо сам как-то с этой ситуацией на приктике не сталкивался :)

А покажи, а то я что-то туплю.

С удовольствием. Сейчас только обеденную партию в Анреал закончим и напишу :)



Шото вроде такого:

Код:
enum SingletonInitState {sisNotInitialized = -1, sisInitializing = 0, sisInitialized = 1};

class Singleton
{
private:

    static Singleton* _instance;

protected:

    Singleton() {}
    Singleton(Singleton const&);
    void operator = (Singleton const&);

public:

    static Singleton* Instance()
    {
        static LONG volatile lock = sisNotInitialized;

        switch (lock)
        {
            case sisNotInitialized:
            {
                if (InterlockedCompareExchange(&lock, sisNotInitialized, sisInitializing) == sisNotInitialized)
                {
                    _instance = new Singleton();
                    lock = sisInitialized;
                    break;
                }
            }
            case sisInitializing:
            {
                while (!_instance)
                {
                    Sleep(0);
                }
                break;
            }
        }

        return _instance;
    }

    virtual ~Singleton() {}
};
 
Останнє редагування:
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #37
Я на самом деле тоже теоритезирую, потомушо сам как-то с этой ситуацией на приктике не сталкивался :)



С удовольствием. Сейчас только обеденную партию в Анреал закончим и напишу :)



Шото вроде такого:

Код:
enum SingletonInitState {sisNotInitialized = -1, sisInitializing = 0, sisInitialized = 1};

class Singleton
{
private:

    static Singleton* _instance;

protected:

    Singleton() {}
    Singleton(Singleton const&);
    void operator = (Singleton const&);

public:

    static Singleton* Instance()
    {
        static LONG volatile lock = sisNotInitialized;

        switch (lock)
        {
            case sisNotInitialized:
            {
                if (InterlockedCompareExchange(&lock, sisNotInitialized, sisInitializing) == sisNotInitialized)
                {
                    _instance = new Singleton();
                    lock = sisInitialized;
                    break;
                }
            }
            case sisInitializing:
            {
                while (!_instance)
                {
                    Sleep(0);
                }
                break;
            }
        }

        return _instance;
    }

    virtual ~Singleton() {}
};

Вроде ниче на первый взгляд. Блестящая идея с интерлоком без мутехов.
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #38
Я на самом деле тоже теоритезирую, потомушо сам как-то с этой ситуацией на приктике не сталкивался :)



С удовольствием. Сейчас только обеденную партию в Анреал закончим и напишу :)



Шото вроде такого:

Код:
enum SingletonInitState {sisNotInitialized = -1, sisInitializing = 0, sisInitialized = 1};

class Singleton
{
private:

    static Singleton* _instance;

protected:

    Singleton() {}
    Singleton(Singleton const&);
    void operator = (Singleton const&);

public:

    static Singleton* Instance()
    {
        static LONG volatile lock = sisNotInitialized;

        switch (lock)
        {
            case sisNotInitialized:
            {
                if (InterlockedCompareExchange(&lock, sisNotInitialized, sisInitializing) == sisNotInitialized)
                {
                    _instance = new Singleton();
                    lock = sisInitialized;
                    break;
                }
            }
            case sisInitializing:
            {
                while (!_instance)
                {
                    Sleep(0);
                }
                break;
            }
        }

        return _instance;
    }

    virtual ~Singleton() {}
};

Идея с интерлоком :клас:
Но теоретически у нас может быть два static LONG volatile lock = sisNotInitialized, а следовательно два инстанса синглетона, один из которых "потеряеться", если два потока одновременно войдут в эту точку.
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #39
Идея с интерлоком :клас:
Но теоретически у нас может быть два static LONG volatile lock = sisNotInitialized, а следовательно два инстанса синглетона, один из которых "потеряеться", если два потока одновременно войдут в эту точку.

Сам понял что сказал?
 
  • 🟡 12:28 Відбій тривоги в Харківська область.Зверніть увагу, тривога ще триває у:- Куп’янський район- Харківський район- Липецька територіальна громада- Вовчанська територіальна громада#Харківська_область
  • #40
Назад
Зверху Знизу