我有一个有趣的问题似乎没有被我在互联网上的研究所解决。 我正在尝试使用dlfcn.h中的函数在我的c ++项目中动态加载库。问题是,当我尝试在运行时重新加载插件时(因为我对它们中的任何一个进行了更改),当调用dlclose()时,主程序崩溃(分段错误(核心转储))。 这是我重现错误的例子:
main.cpp中:
#include <iostream>
#include <dlfcn.h>
#include <time.h>
#include "IPlugin.h"
int main( )
{
void * lib_handle;
char * error;
while( true )
{
std::cout << "Updating the .so" << std::endl;
lib_handle = dlopen( "./test1.so", RTLD_LAZY );
if ( ! lib_handle )
{
std::cerr << dlerror( ) << std::endl;
return 1;
}
create_t fn_create = ( create_t ) dlsym( lib_handle, "create" );
if ( ( error = dlerror( ) ) != NULL )
{
std::cerr << error << std::endl;
return 1;
}
IPlugin * ik = fn_create( );
ik->exec( );
destroy_t fn_destroy = ( destroy_t ) dlsym( lib_handle, "destroy" );
fn_destroy( ik );
std::cout << "Waiting 5 seconds before unloading..." << std::endl;
sleep( 5 );
dlclose( lib_handle );
}
return 0;
}
IPlugin.h:
class IPlugin
{
public:
IPlugin( ) { }
virtual ~IPlugin( ) { }
virtual void exec( ) = 0;
};
typedef IPlugin * ( * create_t )( );
typedef void ( * destroy_t )( IPlugin * );
Test1.h:
#include <iostream>
#include "IPlugin.h"
class Test1 : public IPlugin
{
public:
Test1( );
virtual ~Test1( );
void exec( );
};
Test1.cpp:
#include "Test1.h"
Test1::Test1( ) { }
Test1::~Test1( ) { }
void Test1::exec( )
{
std::cout << "void Test1::exec( )" << std::endl;
}
extern "C"
IPlugin * create( )
{
return new Test1( );
}
extern "C"
void destroy( IPlugin * plugin )
{
if( plugin != NULL )
{
delete plugin;
}
}
编译:
g++ main.cpp -o main -ldl
g++ -shared -fPIC Test1.cpp -o plugin/test1.so
当我在Test1 :: exec方法上更改某些内容(更改要打印的字符串或注释该行)并且主程序休眠时我将新的test1.so复制到主运行目录(cp)时会出现问题)。如果我使用move命令(mv),则不会发生错误。使用cp或mv有什么区别?有没有办法解决这个问题或使用cp来做到这一点?
我正在使用Fedora 14和g ++(GCC)4.5.1 20100924(Red Hat 4.5.1-4)。
提前致谢。
答案 0 :(得分:5)
与此问题相关的cp
和mv
之间的差异如下:
cp
打开目标文件并将新内容写入其中。因此,用新内容替换旧内容。mv
不会触及原始文件的内容。相反,它使目录条目指向新文件。这结果很重要。在应用程序运行时,操作系统会保留对可执行文件和共享对象的打开句柄。当需要查阅其中一个文件时,它会使用相关句柄来访问文件的内容。
cp
,则内容现已损坏,因此可能发生任何事情(段错误很可能会产生结果)。mv
,则打开的文件句柄仍会引用原始文件,即使不再有目录条目,该文件也会继续存在于磁盘上。如果您已使用mv
替换共享对象,则应该能够dlclose
旧的和dlopen
新的共享对象。但是,这不是我已经完成或建议的事情。
答案 1 :(得分:-1)
试试这个:
extern "C"
void destroy( IPlugin * plugin )
{
if( plugin != NULL && dynamic_cast<Test1*>(plugin))
{
delete static_cast<Test1*>(plugin);
}
}