2015-11-03 2 views
2

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

https://social.msdn.microsoft.com/forums/vstudio/en-US/b7701ee5-c9fa-4693-8ae1-d59736360514/question-about-static-variables-in-dll

http://cboard.cprogramming.com/cplusplus-programming/101543-global-static-variable-class-delivered-dll.html

Итак, вот мой вопрос: я работаю над плагином VST, и у меня есть класс, который определен и реализован в DLL. Множество экземпляров этой же DLL загружается, и я бы хотел, чтобы это «счетчик экземпляров», который контролирует, сколько раз класс создается (что происходит только один раз, когда DLL загружается по стандарту VST).

Одним из простых способов сделать это было бы создание статической переменной класса, которую я инициализирую до 0 и увеличивая конструктор/декремент в деструкторе. Я уверен, что знаю, когда мой класс сконструирован и разрушен, но я не уверен в том, будет ли эта статическая переменная класса разделяться между экземплярами моей DLL.

Чтобы уточнить, я загружаю одну и ту же DLL несколько раз; внутри DLL - это класс (используется только внутри DLL-кода и не подвергается действию приложения.) Существует некоторая дискуссия о том, зависит ли поведение данных, определенных в DLL, между Windows и Unix, поэтому я хотел бы знать если делать подобные вещи в DLL безопасно для использования в кросс-платформе.

Пример класса, определенный в DLL, и не подвергается каким-либо образом к приложению загружает DLL (или в противном случае.)

Заголовочный файл

// Foo.h 
# pragma once 
class Foo { 
    static int s_InstanceCount; 
public: 
    Foo(); 
    ~Foo(); 
}; 

А теперь исходный файл

// Foo.cpp 
#include "Foo.h" 
int Foo::s_InstanceCount = 0; 

Foo::Foo() { 
    s_InstanceCount++; 
} 

Foo::~Foo() { 
    s_InstanceCount--; 
    if (s_InstanceCount == 0) { 
     // Do something 
    } 
} 

Конструктор Foo вызывается только тогда, когда DLL загружается приложением (то есть :: LoadLibrary в Windows), а деструктор вызывается только тогда, когда DLL освобождается (т.е. :: FreeLibrary в Windows). Считайте это гарантированным. Будет ли s_InstanceCount использоваться совместно с вызовами конструктора?

EDIT: Как указывает Серый, процесс не может загрузить DLL дважды. Итак, когда моя DLL загружается дважды одним процессом, создаваемые Foo экземпляры существуют в том же пространстве памяти, которое используется процессом загрузки. Возможно ...

+1

Конечно, instanceCount должен быть «атомным». –

+0

Правильно, на практике у меня критический раздел, но мне нужен простой пример. –

+0

Нет, на практике вам нужно «атомное», а не «CRITICAL_SECTION», для этого. 'CRTICAL_SECTION' работает только в процессе, а не в перекрестном процессе. –

ответ

1

Нет, s_InstanceCount в вашем примере будет закрыт для каждого экземпляра библиотеки DLL.Кроме того, без настройки имени файла DLL, вы обычно не можете загружать его несколько раз в том же процессе, как описано здесь: Load the same dll multiple times. Если экземпляры DLL находятся в разных процессах в вашем случае, вам необходимо взаимодействие между процессами, например. через shared memory.

+0

Хммм. Так что, на мой взгляд, на самом деле происходит каждый раз, когда DLL «перезагружается», что ничего не происходит; одни и те же переменные внутри одной DLL доступны одним и тем же процессом. Это то, что я хочу. Благодаря! –

+0

Откуда вы знаете, что DLL «перезагружена»? Я не могу себе представить, как то, что вы описываете, может случиться: когда DLL выгружается, переменные, принадлежащие ей, должны быть уничтожены, поэтому новая загрузка DLL должна получить новые переменные. –

+0

Что делать, если он загружается дважды, прежде чем выгружаться? Для расширения плагин VST3 представляет собой DLL, которая загружается цифровой рабочей станцией (VST3-хост) и обрабатывается как инструмент или эффект; вы можете иметь несколько экземпляров одного и того же плагина, и именно хозяин должен решить, как они это управляют. Это ситуация, с которой я имею дело, где есть несколько экземпляров одного и того же плагина, которые «разделяют» одну и ту же загруженную DLL. –

3

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

This article объясняет это вам. Но это также дает хорошее обходное решение для обмена данными по нескольким процессам с использованием file mapping. Это должно помочь вам решить вашу проблему.

Edit: Существует, по-видимому другое решение, создавая общий сегмент данных (то есть сказать, компоновщик, чтобы поделиться некоторыми из данных, как это делает для кода). Здесь microsoft doc и и proof of concept on codeproject. Я никогда не использовал его, поэтому его нужно тестировать, если он работает и для статических членов класса.

+0

Спасибо! Мне нужны еще несколько персонажей. –

+0

PS: Тем временем я экспериментировал с общим сегментным подходом. Хотя я мог заставить его работать с глобальной или статической переменной, мне не удалось получить общие переменные-члены класса. – Christophe

+0

Общие сегменты данных являются устаревшей технологией, и их следует избегать, поскольку они [небезопасны] (http://blogs.msdn.com/b/oldnewthing/archive/2004/08/04/208003.aspx). –