Одиночная проблема мертвых ссылок - PullRequest
3 голосов
/ 18 августа 2010

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

Я не могу себе представить, когда в другом случае (кроме ссылки на другие синглтоны в dtr), мертвая ссылка будет проблемой. Можете ли вы привести пример из реальной жизни, в котором существует такая проблема, и как я могу ее решить?

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

Ответы [ 6 ]

3 голосов
/ 18 августа 2010

Проблемы порядка уничтожения являются неотъемлемой частью шаблона синглтона.

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

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

  • Не ссылаться на другие синглтоны в ваших деструкторах
  • Явно уничтожить синглетоны в правильном порядке в конце основного
  • Пусть ваши синглеты хранят ссылки на другие синглеты с помощью weak_ptr - они могут быть уничтожены независимо друг от друга, и вы можете безопасно проверить, существует ли ссылочный синглтон, прежде чем использовать его

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

1 голос
/ 18 августа 2010

Скопировано отсюда: Поиск проблем с порядком статической инициализации C ++ (никто бы не пошел по одной ссылке, извините)

См. Также эту статью: Шаблон проектирования C ++ Singleton

Проблемы разрушения:

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

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

class B
{
    public:
        static B& getInstance_Bglob;
        {
            static B instance_Bglob;
            return instance_Bglob;;
        }

        ~B()
        {
             A::getInstance_abc().doSomthing();
             // The object abc is accessed from the destructor.
             // Potential problem.
             // You must guarantee that abc is destroyed after this object.
             // To gurantee this you must make sure it is constructed first.
             // To do this just access the object from the constructor.
        }

        B()
        {
            A::getInstance_abc();
            // abc is now fully constructed.
            // This means it was constructed before this object.
            // This means it will be destroyed after this object.
            // This means it is safe to use from the destructor.
        }
};
1 голос
/ 18 августа 2010

Возможность, которую я не видел вышеупомянутой, и которая может или не может быть приемлемой в зависимости от того, что им удается: размещать Singletons в куче и не разрушать их ... просто позвольте ОС вернуть любые дескрипторыпамять / блокировки и т. д., которые они удерживают при завершении работы приложения (примечание: не работает для всех, например блокировки в общей памяти).

1 голос
/ 18 августа 2010

DumbCoder уже указал вам в правильном направлении.В Modern C ++ design Андрей Александреску объяснил сложные проблемы проектирования с Singletons и показал несколько решений в зависимости от точных требований к синглтону.

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

Чтобы ответить на ваши конкретные вопросы, другой распространенный случай «мертвых» ссылок лучше назвать «нерожденные ссылки» - использование синглтона перед его конструкторомзапустить.Но должно быть очевидно, что поскольку синглеты живут в течение большей части жизни программы, их не существует только в самом начале и в самом конце.

0 голосов
/ 18 августа 2010

Нам не хватает информации, особенно я надеюсь, что мы говорим на C ++ 0x, иначе это будет довольно сложно.

Первое решение - явно управлять вашими синглетами. Большинство проектов, с которыми вы сталкиваетесь в Интернете, ориентированы на простоту и удобство использования за счет правильности в общей ситуации.

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

Естественно, за этим следует идея Singleton Manager, которая является своего рода "супер-синглтоном" и будет создавать экземпляры ваших синглетонов и соответственно их выпускать. Все обращения к синглтону осуществляются через него, чтобы он мог гарантировать, что они доступны при обращении. Еще раз, создание и разрушение происходит в однопоточной ситуации.

Становится намного сложнее, когда мы говорим о отложенной инициализации (по требованию). Наиболее простой схемой для этого является локальная статическая переменная:

MySingleton& Get() { static MySingleton M; return M; }

C ++ 0x, наконец, гарантирует, что будет создан только один экземпляр MySingleton, что значительно облегчит работу! Однако у вас здесь есть проблема «мертвой ссылки».

В C ++ порядок уничтожения статических объектов просто противоположен порядку построения, поэтому одно из решений состоит в том, чтобы предписать использовать в конструкторах любой синглтон, используемый в деструкторе одноэлементного объекта (ВСЕ из них). Таким образом, вы на самом деле гарантируете, что он будет построен до и, следовательно, разрушен после.

Обратите внимание, что ленивое создание экземпляров сложно в многопоточной среде в C ++ 03 (или раньше), потому что не было никакой гарантии, что будет создан один экземпляр ... и в этот момент чрезвычайно трудно получить блокировку (после все, мьютекс сам по себе одноэлементный ... не так ли?).

0 голосов
/ 18 августа 2010

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

Таким образом, вы можете создать функцию init для вашего приложения (и сделатьуверен, что это самая первая вещь, которая будет вызываться в вашей основной функции).

Внутри этой функции вызывайте одноэлементные функции доступа в том порядке, в котором вы хотите, чтобы они были созданы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...