Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 复制动态库时dlclose崩溃_C++_G++_Dynamic Linking - Fatal编程技术网

C++ 复制动态库时dlclose崩溃

C++ 复制动态库时dlclose崩溃,c++,g++,dynamic-linking,C++,G++,Dynamic Linking,我有一个有趣的问题,我在互联网上的研究似乎没有解决。 我试图用DLFCN .h函数在C++项目中动态加载库。问题是,当我试图在运行时重新加载插件时(因为我对任何插件都做了更改),调用dlclose()时主程序崩溃(分段错误(内核转储))。 下面是我重现错误的示例: main.cpp: #include <iostream> #include <dlfcn.h> #include <time.h> #include "IPlugin.h"

我有一个有趣的问题,我在互联网上的研究似乎没有解决。 我试图用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;
}
测试1.h:

#include    <iostream>
#include    "IPlugin.h"

class Test1 : public IPlugin
{
public:
    Test1( );
    virtual ~Test1( );

    void exec( );
};
例如,当我在Test1::exec方法上更改某些内容(更改要打印的字符串或对行进行注释)并且在主程序睡眠时,我将新的Test1.so复制到主运行目录(cp)时,就会出现问题。如果使用move命令(mv),则不会发生错误。使用cp或mv有什么区别?有没有办法解决这个问题,或者使用cp解决这个问题

我将Fedora14与g++(GCC)4.5.12000924(Red Hat 4.5.1-4)一起使用


提前感谢。

与此问题相关的
cp
mv
之间的区别如下:

  • cp
    打开目标文件并将新内容写入其中。因此,它将用新内容替换旧内容
  • mv
    不接触原始文件的内容。相反,它使目录入口指向新文件
  • 事实证明这很重要。当应用程序运行时,操作系统将打开可执行文件和共享对象的句柄。当它需要查阅其中一个文件时,它会使用相关的句柄来访问该文件的内容

  • 如果您使用了
    cp
    ,则内容现在已损坏,因此任何情况都可能发生(segfault很可能是一种结果)
  • 如果使用了
    mv
    ,则打开的文件句柄仍然引用原始文件,该文件仍然存在于磁盘上,即使不再有该文件的目录项
  • 如果您已使用
    mv
    替换共享对象,则应能够
    dlclose
    旧对象和
    dlopen
    新对象。然而,这并不是我已经做过或将要推荐的事情。

    试试这个:

    extern "C"
    void destroy( IPlugin * plugin )
    {
        if( plugin != NULL && dynamic_cast<Test1*>(plugin))
        {
            delete static_cast<Test1*>(plugin);
        }
    }
    
    extern“C”
    无效销毁(IPlugin*插件)
    {
    if(插件!=NULL&&dynamic_cast(插件))
    {
    删除静态_cast(插件);
    }
    }
    
    我认为这是因为
    RTLD\u懒惰
    ,现在就试试
    RTLD\u
    。很好的问题组合。要是所有的新成员都那么擅长写质量问题就好了!我已经用RTLD_NOW和前面提到的两个选项(RTLD_LAZY和RTLD_NOW)或RTLD_GLOBAL和RTLD_LOCAL对它进行了测试。结果保持不变…实现这一点的最佳方法通常是使用
    install
    命令。这应该是注释,而不是答案。
    #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
    
    extern "C"
    void destroy( IPlugin * plugin )
    {
        if( plugin != NULL && dynamic_cast<Test1*>(plugin))
        {
            delete static_cast<Test1*>(plugin);
        }
    }