невозможно успешно вызвать функцию в динамически загружаемом плагине в C ++ - PullRequest
4 голосов
/ 16 января 2010

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

Плагин - это абстрактный класс с несколькими не виртуальными функциями и несколькими защищенными переменными (одной из них является std :: vector refList).

Класс plugin_loader успешно загружает и даже вызывает виртуальный метод в загруженном классе (а именно: «std :: string plugin :: getName ()».

Основная функция создает экземпляр "хоста", который содержит вектор умных указателей с подсчетом ссылок refptr для класса "плагин". Затем main создает экземпляр plugin_loader, который фактически выполняет dlopen / dlsym, и создает экземпляр refptr, передавая ему create_instance (). Наконец, он передает созданный refptr обратно в функцию хоста addPlugin. host :: addPlugin успешно вызывает несколько функций в переданном экземпляре плагина и, наконец, добавляет его в вектор >.

Затем основная функция подписывается на несколько событий Apple и вызывает RunApplicationEventLoop (). Обратный вызов события декодирует результат, а затем вызывает функцию в host, host :: sendToPlugin, которая идентифицирует плагин, для которого предназначено событие, и затем вызывает обработчик в плагине. В этот момент все перестает работать.

host :: sendToPlugin считывает результат и определяет плагин, на который отправляется событие.

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

Любой вызов любой виртуальной функции в плагине в векторе вызывает исключение плохого доступа. Я попытался заменить refptrs обычными указателями, а также boost :: shared_ptrs, и я получаю одно и то же исключение. Я знаю, что экземпляр плагина действителен, так как я могу исследовать экземпляр в отладчике Xcode и даже просматривать элементы в refList плагина.

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

Есть идеи, почему это происходит?

class plugin
{
public:
    virtual std::string getName(); 

protected:
    std::vector<std::string> refList;
};

и класс pluginLoader:

template<typename T> class pluginLoader 
{
    public: pluginLoader(std::string path);
    // initializes private mPath string with path to dylib

    bool open(); 
    // opens the dylib and looks up the createInstance function. Returns true if successful, false otherwise

    T * create_instance(); 
    // Returns a new instance of T, NULL if unsuccessful
}; 

class host
{
public:
      addPlugin(int id, plugin * plug);
      sendToPlugin(); // this is the problem method
      static host * me;

private:
     std::vector<plugin *> plugins; // or vector<shared_ptr<plugin> > or vector<refptr<plugin> >
};

код события яблока из host.cpp;

host * host::me;
pascal OSErr HandleSpeechDoneAppleEvent(const AppleEvent *theAEevt, AppleEvent *reply, SRefCon refcon) {
         // this is all boilerplate taken straight from an apple sample except for the host::me->ae_callback line
         OSErr status = 0;
         Result result = 0;
         // get the result
         if (!status) {
             host::me->ae_callback(result);
         }
         return status;
}
void host::ae_callback(Result result) {
       OSErr err;
       // again, boilerplate apple code
   // grab information from result
       if (!err)
         sendToPlugin();
}
void host::sendToPlugin() {
       // calling *any* method in plugin results in failure regardless of what I do
}

РЕДАКТИРОВАТЬ: Это выполняется на OSX 10.5.8, и я использую GCC 4.0 с Xcode. Это , а не , предназначенное для кроссплатформенного приложения.

РЕДАКТИРОВАТЬ: Чтобы было ясно, плагин работает до тех пор, пока предоставленный Apple цикл событий не вызовет мою функцию обратного вызова. Когда функция обратного вызова вызывает обратно в хост, когда все перестает работать. Это моя проблема, все остальное до этого момента работает.

Ответы [ 2 ]

1 голос
/ 16 января 2010

Не видя весь ваш код, будет непросто понять, что именно идет не так. Некоторые вещи, на которые стоит посмотреть:

  • Убедитесь, что компоновщик ничего не выбрасывает. В gcc попробуйте параметры компиляции -Wl -E - мы используем это в Linux, но, похоже, не нашли в этом необходимости на Mac.
  • Убедитесь, что вы случайно не выгружаете динамическую библиотеку, прежде чем закончить с ней. RAII не работает для выгрузки динамических библиотек, если только вы не остановите исключения на границе динамической библиотеки.

Возможно, вы захотите изучить нашу подключаемую библиотеку, которая работает на Linux, Mac и Windows. Код динамической загрузки (вместе с загрузкой других библиотечных материалов) доступен по адресу http://svn.felspar.com/public/fost-base/trunk/

Мы не используем механизм dlsym - его сложно использовать правильно (и переносимо). Вместо этого мы создаем библиотеку плагинов по имени и помещаем туда, в основном, фабрики. Вы можете проверить, как это работает, посмотрев на способ динамической загрузки .so с тестовыми наборами. Пример загрузчика: http://svn.felspar.com/public/fost-base/trunk/fost-base/Cpp/fost-ftest/ftest.cpp, а регистрация набора тестов - http://svn.felspar.com/public/fost-base/trunk/fost-base/Cpp/fost-test/testsuite.cpp. Threadsafe_store содержит фабрики по имени, а конструктор набора регистрирует фабрику.

0 голосов
/ 16 января 2010

Я полностью упустил тот факт, что я вызывал dlclose в dtor моего plugin_loader и по какой-то причине плагины разрушались между вызовом RunApplicatoinEventLoop и вызовом sendToPlugin. Я удалил dlclose, и теперь все работает.

...