• dlopen重复打开的一些问题


    dlopen重复打开的一些问题

    源码地址: https://gitee.com/layty/test-dlopen
    如果打开多个动态库(软连接的),会共享内存吗?

    结论: 会

    如果动态库更新了,不close,直接open,会更新吗?

    结论: 不会,要先close,再open即可

    动态库源码如下

    #include <iostream>
    extern "C"{
    void say_hello(){
        static int i=0;
        std::cout << "Hello, from dlopen!" << i++ << std::endl;
    }
    }
    

    一个动态库打开多次

    结论:同一个句柄,这个直接在man手册有讲的

    #include <iostream>
    #include <dlfcn.h>    // dlopen, dlerror, dlsym, dlclose
    typedef void(*say_hello)(void);
    const char* dllPath = "./libdlopen.so";
    int main()
    {
        for(int i=0;i<10;i++)
        {
            void* handle = dlopen( dllPath, RTLD_LAZY );
            if( !handle )
            {
                fprintf( stderr, "[%s](%d) dlopen get error: %s\n", __FILE__, __LINE__, dlerror() );
                exit( EXIT_FAILURE );
            }
            else
            {
                std::cout << "handle addr is " << handle << std::endl;
            }
            say_hello fun = (say_hello)dlsym( handle, "say_hello" );
            //std::cout << "handle addr is close " << handle << std::endl;
            //dlclose(handle);
        }
    }
    

    输出

    layty@ubuntu:~/work/Test/dlopen/build$ ./main1
    handle addr is 0x55692beb3ed0
    handle addr is 0x55692beb3ed0
    handle addr is 0x55692beb3ed0
    handle addr is 0x55692beb3ed0
    handle addr is 0x55692beb3ed0
    handle addr is 0x55692beb3ed0
    handle addr is 0x55692beb3ed0
    handle addr is 0x55692beb3ed0
    handle addr is 0x55692beb3ed0
    handle addr is 0x55692beb3ed0
    

    如果是关闭后重新打开呢

    //std::cout << "handle addr is close " << handle << std::endl;
    //dlclose(handle);
    

    输出还是

    handle addr is 0x55725a3eaed0
    handle addr is close 0x55725a3eaed0
    handle addr is 0x55725a3eaed0
    handle addr is close 0x55725a3eaed0
    handle addr is 0x55725a3eaed0
    handle addr is close 0x55725a3eaed0
    handle addr is 0x55725a3eaed0
    handle addr is close 0x55725a3eaed0
    handle addr is 0x55725a3eaed0
    handle addr is close 0x55725a3eaed0
    handle addr is 0x55725a3eaed0
    handle addr is close 0x55725a3eaed0
    handle addr is 0x55725a3eaed0
    handle addr is close 0x55725a3eaed0
    handle addr is 0x55725a3eaed0
    handle addr is close 0x55725a3eaed0
    handle addr is 0x55725a3eaed0
    handle addr is close 0x55725a3eaed0
    handle addr is 0x55725a3eaed0
    handle addr is close 0x55725a3eaed
    

    使用软连接创建多个动态库

    结论: 唯一的句柄,内存共享

    layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.2.so
    layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.3.so
    layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.4.so
    layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.5.so
    layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.6.so
    layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.7.so
    layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.8.so
    layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.9.so
    layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.0.so
    

    然后直接多次打开

    #include <iostream>
    #include <dlfcn.h>    // dlopen, dlerror, dlsym, dlclose
    
    
    typedef void(*say_hello)(void);
    const char* dllPath = "./libdlopen.so";
    
    int main()
    {
        for(int i=0;i<10;i++)
        {
            char dllPathsoft[100];
            snprintf(dllPathsoft,sizeof(dllPathsoft),"%s.%d.so",dllPath,i);
    
            void* handle = dlopen( dllPathsoft, RTLD_LAZY );
            if( !handle )
            {
                
                fprintf( stderr, "[%s](%d)@%s dlopen get error: %s\n", __FILE__, __LINE__, dllPathsoft,dlerror() );
                exit( EXIT_FAILURE );
            }
            else
            {
                std::cout << "handle addr is " << handle << std::endl;
            }
            say_hello fun = (say_hello)dlsym( handle, "say_hello" );
            //std::cout << "handle addr is close " << handle << std::endl;
            // dlclose(handle);
        }
    }
    

    输出

    handle addr is 0x55acb4ee8ed0
    Hello, from dlopen!0
    handle addr is 0x55acb4ee8ed0
    Hello, from dlopen!1
    handle addr is 0x55acb4ee8ed0
    Hello, from dlopen!2
    handle addr is 0x55acb4ee8ed0
    Hello, from dlopen!3
    handle addr is 0x55acb4ee8ed0
    Hello, from dlopen!4
    handle addr is 0x55acb4ee8ed0
    Hello, from dlopen!5
    handle addr is 0x55acb4ee8ed0
    Hello, from dlopen!6
    handle addr is 0x55acb4ee8ed0
    Hello, from dlopen!7
    handle addr is 0x55acb4ee8ed0
    Hello, from dlopen!8
    handle addr is 0x55acb4ee8ed0
    Hello, from dlopen!9
    

    如果中间close了呢

    内存映射的句柄还是一样,但是变量已经被释放了

    layty@ubuntu:~/work/Test/dlopen/build$ ./main4
    handle addr is 0x55d04e7bbed0
    Hello, from dlopen!0
    handle addr is close 0x55d04e7bbed0
    handle addr is 0x55d04e7bbed0
    Hello, from dlopen!0
    handle addr is close 0x55d04e7bbed0
    handle addr is 0x55d04e7bbed0
    Hello, from dlopen!0
    handle addr is close 0x55d04e7bbed0
    handle addr is 0x55d04e7bbed0
    Hello, from dlopen!0
    handle addr is close 0x55d04e7bbed0
    handle addr is 0x55d04e7bbed0
    Hello, from dlopen!0
    handle addr is close 0x55d04e7bbed0
    handle addr is 0x55d04e7bbed0
    Hello, from dlopen!0
    handle addr is close 0x55d04e7bbed0
    handle addr is 0x55d04e7bbed0
    Hello, from dlopen!0
    handle addr is close 0x55d04e7bbed0
    handle addr is 0x55d04e7bbed0
    Hello, from dlopen!0
    handle addr is close 0x55d04e7bbed0
    handle addr is 0x55d04e7bbed0
    Hello, from dlopen!0
    handle addr is close 0x55d04e7bbed0
    handle addr is 0x55d04e7bbed0
    Hello, from dlopen!0
    handle addr is close 0x55d04e7bbed0
    

    复制动态库

    结论: 会有不同的地址映射

    cp  libdlopen.so libdlopen.so.10.so
    cp  libdlopen.so libdlopen.so.11.so
    cp  libdlopen.so libdlopen.so.12.so
    cp  libdlopen.so libdlopen.so.13.so
    cp  libdlopen.so libdlopen.so.14.so
    cp  libdlopen.so libdlopen.so.15.so
    cp  libdlopen.so libdlopen.so.16.so
    cp  libdlopen.so libdlopen.so.17.so
    cp  libdlopen.so libdlopen.so.18.so
    cp  libdlopen.so libdlopen.so.19.so
    

    测试代码

    #include <iostream>
    #include <dlfcn.h>    // dlopen, dlerror, dlsym, dlclose
    
    
    typedef void(*say_hello)(void);
    const char* dllPath = "./libdlopen.so";
    
    int main()
    {
        for(int i=10;i<20;i++)
        {
            char dllPathsoft[100];
            snprintf(dllPathsoft,sizeof(dllPathsoft),"%s.%d.so",dllPath,i);
    
            void* handle = dlopen( dllPathsoft, RTLD_LAZY );
            if( !handle )
            {
                
                fprintf( stderr, "[%s](%d)@%s dlopen get error: %s\n", __FILE__, __LINE__, dllPathsoft,dlerror() );
                exit( EXIT_FAILURE );
            }
            else
            {
                std::cout << "handle addr is " << handle << std::endl;
            }
            say_hello fun = (say_hello)dlsym( handle, "say_hello" );
            fun();
            //std::cout << "handle addr is close " << handle << std::endl;
            // dlclose(handle);
        }
    }
    

    输出

    layty@ubuntu:~/work/Test/dlopen/build$ ./main5 
    handle addr is 0x55e15ac76ed0
    Hello, from dlopen!0
    handle addr is 0x55e15ac77940
    Hello, from dlopen!0
    handle addr is 0x55e15ac77fa0
    Hello, from dlopen!0
    handle addr is 0x55e15ac78600
    Hello, from dlopen!0
    handle addr is 0x55e15ac78c60
    Hello, from dlopen!0
    handle addr is 0x55e15ac792c0
    Hello, from dlopen!0
    handle addr is 0x55e15ac79920
    Hello, from dlopen!0
    handle addr is 0x55e15ac79f80
    Hello, from dlopen!0
    handle addr is 0x55e15ac7a5e0
    Hello, from dlopen!0
    handle addr is 0x55e15ac7ac40
    Hello, from dlopen!0
    

    如果复制之后关闭呢

    可以看到句柄是一样的

    layty@ubuntu:~/work/Test/dlopen/build$ ./main6
    handle addr is 0x564ba76c4ed0
    Hello, from dlopen!0
    handle addr is close 0x564ba76c4ed0
    handle addr is 0x564ba76c4ed0
    Hello, from dlopen!0
    handle addr is close 0x564ba76c4ed0
    handle addr is 0x564ba76c4ed0
    Hello, from dlopen!0
    handle addr is close 0x564ba76c4ed0
    handle addr is 0x564ba76c4ed0
    Hello, from dlopen!0
    handle addr is close 0x564ba76c4ed0
    handle addr is 0x564ba76c4ed0
    Hello, from dlopen!0
    handle addr is close 0x564ba76c4ed0
    handle addr is 0x564ba76c4ed0
    Hello, from dlopen!0
    handle addr is close 0x564ba76c4ed0
    handle addr is 0x564ba76c4ed0
    Hello, from dlopen!0
    handle addr is close 0x564ba76c4ed0
    handle addr is 0x564ba76c4ed0
    Hello, from dlopen!0
    handle addr is close 0x564ba76c4ed0
    handle addr is 0x564ba76c4ed0
    Hello, from dlopen!0
    handle addr is close 0x564ba76c4ed0
    handle addr is 0x564ba76c4ed0
    Hello, from dlopen!0
    handle addr is close 0x564ba76c4ed0
    

    动态更新动态库

    main7不close直接open 不会更新,也应该这样,否则内存什么的怎么处理

    再写一个so

    #include <iostream>
    
    extern "C"{
    
    void say_hello(){
        static int i=0;
        std::cout << "Hello, from dlopen new!" << i++ << std::endl;
    }
    
    }
    

    测试的源码

    #include <iostream>
    #include <dlfcn.h>    // dlopen, dlerror, dlsym, dlclose
    
    
    typedef void(*say_hello)(void);
    const char* dllPath = "./libdlopen.so.main7.so";
    
    int main()
    {
        for(int i=0;i<2;i++)
        {
            void* handle = dlopen( dllPath, RTLD_LAZY );
            if( !handle )
            {
                fprintf( stderr, "[%s](%d) dlopen get error: %s\n", __FILE__, __LINE__, dlerror() );
                exit( EXIT_FAILURE );
            }
            else
            {
                std::cout << "handle addr is " << handle << std::endl;
            }
            say_hello fun = (say_hello)dlsym( handle, "say_hello" );
            std::cout << "handle addr is close " << handle << std::endl;
            fun();
            
            std::cout << "wait to replace so " << handle << std::endl;
            getchar();
            dlclose(handle);
        }
    }
    

    执行如下

    ln -sf libdlopen.so  ./libdlopen.so.main7.so
    
    ln -sf libdlopen2.so  ./libdlopen.so.main7.so
    
    
    layty@ubuntu:~/work/Test/dlopen/build$ ./main7 
    handle addr is 0x55a2dd4f7ed0
    handle addr is close 0x55a2dd4f7ed0
    Hello, from dlopen!0
    wait to replace so 0x55a2dd4f7ed0
    ----------------------------------------------------------------使用软连接换掉so
    handle addr is 0x55a2dd4f7ed0
    handle addr is close 0x55a2dd4f7ed0
    Hello, from dlopen!1
    wait to replace so 0x55a2dd4f7ed0
    

    使用close再去打开main8

     ln -sf libdlopen2.so  
    layty@ubuntu:~/work/Test/dlopen/build$ ./main8
    handle addr is 0x55fec2ce8ed0
    handle addr is close 0x55fec2ce8ed0
    Hello, from dlopen!0
    wait to replace so 0x55fec2ce8ed0
    --------------------------------------------------这个地方使用 新开一个终端执行ln -sf libdlopen2.so  ./libdlopen.so.main7.so
    handle addr is 0x55fec2ce8ed0
    handle addr is close 0x55fec2ce8ed0
    Hello, from dlopen new!0-----------------------------可以看到so使用新的,类似于热更新了
    wait to replace so 0x55fec2ce8ed0
    
  • 相关阅读:
    学习链接
    【转】C#学习路线WinForm学习路线
    WPF 等待动画控件
    wpf 设置窗体在屏幕的初始位置
    WPF 添加右键菜单 自定义透明控件
    记录自己的点滴
    Linux下的mysql默认大小写敏感
    springboot+mybatis遇到BUG:自动注入失败
    springboot在阿里CentOS 7后台永久运行
    阿里云CentOS7 64位安装jdk8和mysql5.6.43及远程连接mysql
  • 原文地址:https://www.cnblogs.com/zongzi10010/p/16415920.html
Copyright © 2020-2023  润新知