Время жизни Singelton в dll/пакете

Если я создаю одноэлементный класс в контексте dll или пакета на Mac, экземпляр одноэлементного класса создается один раз и используется всеми экземплярами dll. Я использую dll в качестве плагина для приложения. Теперь мне пришло в голову следующее: если я использую одноэлементный класс, он будет общим для нескольких экземпляров плагина. Однако это затрудняет эффективное управление временем жизни одноэлементного класса. Единственный способ, который я мог придумать, - это использовать счетчик ссылок и заставить синглтон удалить себя, когда счетчик ссылок равен 0.

У кого-нибудь есть лучшие идеи по этому поводу? Есть ли хороший способ ограничить одноэлементный объект одним экземпляром dll?

Язык — С++, но решение должно работать под Windows и Mac (здесь это комплект). Спецификация для dll или пакета задается приложением, поэтому здесь ничего не меняется.


person st-h    schedule 20.02.2011    source источник
comment
Я не уверен, как все работает в Windows, но в операционных системах * nix синглтон, определенный в библиотеке общих объектов, не будет совместно использоваться приложениями, поскольку каждый процесс имеет свое собственное адресное пространство, поэтому, если вы явно не используете общее механизм памяти вашей ОС, никакие объекты не должны использоваться совместно приложениями.   -  person David Claridge    schedule 21.02.2011
comment
Я не говорю здесь о совместном использовании между приложениями. Я говорю об экземплярах плагина, который используется в одном приложении. (хотя может быть более одного приложения, но это усложнит понимание) Дело в том, что я не хочу создавать синглтон, когда он нужен в первый раз. удалите подключаемый модуль и оставьте экземпляр singleton плавающим в памяти. Вот почему я подумал о подсчете ссылок.   -  person st-h    schedule 21.02.2011


Ответы (2)


Вот мое золотое правило относительно DLL и C++.

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

Просто становится грязно, пытаясь экспортировать каждый метод каждого класса из DLL. Дело в компонентах и ​​интерфейсах.

Поскольку вы сказали DLL, это подразумевает Windows. COM — это ответ. КОМ твой друг. Создайте COM-DLL, и ваша проблема с подсчетом ссылок в основном решена. Используйте библиотеки шаблонов ATL (CComObjectRootEx и другие), чтобы сделать реализацию действительно простой. Немного сложно экспортировать синглтон класса C++ с помощью COM. Самый простой подход состоит в том, чтобы класс COM "обертывал" синглтон и просто перенаправлял все вызовы методов в реальный экземпляр синглтона.

Теперь, если вы не знакомы с объектной моделью компонентов, кривая обучения может быть немного крутой. (И большинство справочников тратят слишком много времени на внепроцессные COM, прокси/заглушки DLL, автоматизацию, IDispatch - ни один из них не имеет отношения к вашей проблеме).

Теперь, если у вас нет времени на изучение COM, вот примерная схема реализации одноэлементного шаблона DLL без COM.

// singleton.h (consumed by DLL and users of your singleton)
// IMySingleton is an interface class.  It only defines pure virtual methods
class IMySingleton
{
public:
    virtual int DoSomething()=0;
    virtual int DoSomethingElse()=0;

    virtual void AddRef()=0;
    virtual void Release()=0;
};

// returns back an instance of IMySingleton with the refcount already at "1"
// This function gets exported out of your DLL(either via .def file or __declexport attribute)
HRESULT GetMySingletonInstance(IMySingleton** ppMySingleton);
// -------------------------------------



// singleton.cpp (compiled into your DLL - but is NOT exported out of the DLL)
class CMySingleton : public IMySingleton
{
public:
    int m_refcount;
    static CMySingleton* s_pInstance;

    // returns an adref'd instance of the singleton
    static CMySingleton* GetInstance()
    {
        if (s_pInstance == NULL)
        {
           s_pInstance = new CMySingleton(); // refcount at 1
        }
        else
        {
           s_pInstance->AddRef();
        }

        return s_pInstance;
    }

    CMySingleton()
    {
       m_refcount = 1;
       // your initialization code goes here
    }

    ~CMySingleton()
    {
       // cleanup code
    }

    int DoSomething()
    {
        /// your code goes here
        return x;
    }

    int DoSomethingElse()
    {
        /// your code goes here
        return y;
    }
    void AddRef() {m_refcount++;}
    void Release()
    {
        m_refcount--;
        if (m_refcount == 0)
        {
            s_pInstance = NULL;
            delete this;
        }
    }

};

// exported out of the DLL
HRESULT GetMySingletonInstance(IMySingleton** ppSingleton)
{
    *ppSingleton = static_cast<IMySingleton*>(CMySingleton::GetInstance());
}

Вызывающие объекты, которым требуется доступ к службам синглтона, должны вызвать GetMySingletonInstance только один раз. Когда они уходят, они просто освобождают экземпляр синглтона, вызывая Release() для экземпляра указателя, который у них есть.

person selbie    schedule 21.02.2011
comment
спасибо за Ваш ответ. однако я не думаю, что это делает то, что мне нужно. Я использую синглтон в dll, но мне не нужно его экспортировать. Во-вторых, я не могу изменить экспорт dll. Он предоставляется приложением, которое его использует. Я только что обновил свой вопрос, надеюсь, теперь он достаточно конкретен. - person st-h; 21.02.2011

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

Использование подсчета ссылок — отличная идея, существует несколько так называемых "shared-pointer" библиотек, которые могут помочь вам в ее реализации. Вот реализация, которую я часто использую: http://www.boost.org/doc/libs/1_45_0/libs/smart_ptr/shared_ptr.htm

person Maarten    schedule 20.02.2011
comment
для того, что я читал и тестировал, используется простой синглтон. Однако в настоящее время я тестирую на Mac с использованием пакетов ... возможно, окна здесь ведут себя по-другому. В конце концов, решение должно быть кроссплатформенным. - person st-h; 21.02.2011
comment
Если вы имеете в виду общие библиотеки, не используйте термин DLL. DLL — это специфичная для Microsoft реализация общих библиотек. - person Maarten; 21.02.2011
comment
Спасибо за подсказку. Однако часть Windows на самом деле является dll. Вот еще один вопрос с этого веб-сайта, в котором также говорится, что синглтон в dll является общим для экземпляров: stackoverflow.com/questions/4624768/ Итак, я не думаю, что окна здесь исключение. - person st-h; 21.02.2011