• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            S.l.e!ep.¢%

            像打了激速一樣,以四倍的速度運轉,開心的工作
            簡單、開放、平等的公司文化;尊重個性、自由與個人價值;
            posts - 1098, comments - 335, trackbacks - 0, articles - 1
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            Linux下C++ hot reload

            Posted on 2011-07-01 17:03 S.l.e!ep.¢% 閱讀(1346) 評論(0)  編輯 收藏 引用 所屬分類: Unix

            Linux下C++熱加載實例

            Friday, 3. June 2011 - 16:21 |1 comment ?

            假設一種環境,我們要對服務熱拔插一個動態庫(.so文件),所要考慮的是多線程環境的兼容,不會因為動態庫替換后造成棧損毀而崩潰
            這邊想到的方法就是封裝一個dlopen過程作為對象實例加載(見load_so.h),當發出更新動態庫時重新dlopen過程,替換原先的實例,注意這個替換過程必須是溫和的、無逢的,這邊我們使用智能指針實現。

            具體更新的實現通過一個單例(見do_sth.h),調用Reload重新加載動態庫。

            我們構造一個極簡單的動態庫測試:
            make_so.h

            1
            2
            3
            4
            5
            6
            7
            8
            #include "say.h"
            extern "C"
            {
            ? ? void Enter(const std::string&str)
            ? ? {
            ? ? ? ? Say::instance().Sth(str); ? //在這里動態庫又過來調用了主程序的單件
            ? ? }
            }

            say.h 打印消息,這邊只是聲明一個單例,具體實現于主程序當中

            1
            2
            3
            4
            5
            6
            #include "singleton.h"
            class Say :public Singleton <Say>
            {
            ? ? public:
            ? ? ? ? void Sth(const std::string&str);
            };

            通過編譯生test.so:
            g++ make_so.cpp -fPIC -shared -pthread -rdynamic -lboost_thread -lboost_system -o test.so -L[boost庫目錄]

            主程序 test.cpp ,用來測試這個動態庫test.so

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            27
            28
            29
            30
            31
            32
            33
            34
            35
            36
            37
            38
            39
            40
            41
            42
            43
            44
            45
            46
            47
            48
            49
            50
            51
            52
            53
            54
            55
            56
            57
            58
            59
            60
            61
            62
            63
            64
            65
            66
            67
            68
            69
            #include <boost/thread.hpp>
            #include "load_so.h"
            #include "say.h"

            class DoSth :public Singleton
            {
            ? ? public:
            ? ? ? ? DoSth():m_so(new LoadSo("./test.so"))
            ? ? ? ? {
            ? ? ? ? }

            ? ? ? ? DynamicSo_ptr Get()
            ? ? ? ? {
            ? ? ? ? ? ? boost::mutex::scoped_lock lock(m_mtx);
            ? ? ? ? ? ? return m_so;
            ? ? ? ? }

            ? ? ? ? void Reload()
            ? ? ? ? {
            ? ? ? ? ? ? boost::mutex::scoped_lock lock(m_mtx);
            ? ? ? ? ? ? m_so.reset(new LoadSo("./test.so"));
            ? ? ? ? }
            ? ? private:
            ? ? ? ? DynamicSo_ptr m_so;
            ? ? ? ? boost::mutex m_mtx;
            };



            /// Say
            void Say::Sth(const std::string&str)
            {
            ? ? std::cout<< str << std::endl;
            }




            ////////////////////////// 測試代碼 //////////////////////////////////////

            //更新動態庫
            void test()
            {
            ? ? for(int i=0;i<100;++i)
            ? ? {
            ? ? ? ? sleep(1);
            ? ? ? ? DoSth::instance().Reload();
            ? ? }
            }

            //運行動態庫
            void test2()
            {
            ? ? for(int i=0;irun("12");
            ? ? }
            }

            int main()
            {
            ? ? std::cout<<"run\n";

            ? ? boost::thread thread1(&test2);
            ? ? boost::thread thread2(&test);

            ? ? thread1.join();
            ? ? thread2.join();

            ? ? return0;
            }

            編譯主程序:

            g++ -Wall test2.cpp -o test2 -pipe -pthread -ldl -Wl,–export-dynamic -lboost_system -lboost_thread -L[boost庫目錄]

            這邊一定要加“-Wl,–export-dynamic”以便導出主程序的符號供動態庫回調。

            編譯成功后生成 test 可執行文件,運行:

            #./test
            run
            12
            12
            12
            12
            ….

            假設這時我們修改 make_so.h

            1
            2
            3
            4
            5
            6
            7
            8
            #include "say.h"
            extern "C"
            {
            ? ? void Enter(const std::string&str)
            ? ? {
            ? ? ? ? Say::instance().Sth(str +",ab"); ? //修改輸出
            ? ? }
            }

            g++ make_so.cpp -fPIC -shared -pthread -rdynamic -lboost_thread -lboost_system -o test.so -L[boost庫目錄]
            重新編譯后,這時我們主程序會馬上響應,輸出:

            12,ab
            12,ab
            12,ab
            12,ab
            ….

            說明熱替換是成功的。

            在實際運用中,當要替換動態庫時可以在程序中使用
            DoSth::instance().Reload();
            具體方法很多,可以通過socket、中斷信號、監聽文件系統、定時更新等方式。

            load_so.h 代碼:

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            27
            28
            29
            30
            31
            32
            33
            34
            35
            36
            37
            38
            39
            40
            41
            42
            43
            44
            45
            46
            47
            48
            49
            50
            51
            52
            53
            54
            55
            56
            57
            58
            59
            #ifndef LOAD_SO_H
            #define LOAD_SO_H

            #include
            #include
            #include
            using namespace std;

            class LoadSo
            {
            ? ? typedefvoid(*Func)(const std::string&suid);
            ? ? public:
            ? ? ? ? LoadSo(constchar* so_file)
            ? ? ? ? {
            ? ? ? ? ? ? load(so_file);
            ? ? ? ? }

            ? ? ? ? ~LoadSo()
            ? ? ? ? {
            ? ? ? ? ? ? Close();
            ? ? ? ? }

            ? ? ? ? void Close()
            ? ? ? ? {
            ? ? ? ? ? ? dlclose(m_handle);
            ? ? ? ? }

            ? ? ? ? void run(const std::string&str )
            ? ? ? ? {
            ? ? ? ? ? ? m_func(str);
            ? ? ? ? }
            ? ? private:
            ? ? ? ? bool load(constchar* so_file)
            ? ? ? ? {
            ? ? ? ? ? ? m_handle = dlopen(so_file, RTLD_LAZY);
            ? ? ? ? ? ? if(!m_handle){
            ? ? ? ? ? ? ? ? std::string error("Cannot open library: ");
            ? ? ? ? ? ? ? ? throw std::runtime_error(error + dlerror());
            ? ? ? ? ? ? ? ? returnfalse;
            ? ? ? ? ? ? }

            ? ? ? ? ? ? dlerror();
            ? ? ? ? ? ? m_func =(Func) dlsym(m_handle, "Enter");
            ? ? ? ? ? ? constchar*dlsym_error = dlerror();
            ? ? ? ? ? ? if(dlsym_error){
            ? ? ? ? ? ? ? ? dlclose(m_handle);
            ? ? ? ? ? ? ? ? std::string error("Cannot load symbol: ");
            ? ? ? ? ? ? ? ? throw std::runtime_error(error + dlsym_error);
            ? ? ? ? ? ? ? ? returnfalse;
            ? ? ? ? ? ? }
            ? ? ? ? ? ? returntrue;
            ? ? ? ? }

            ? ? ? ? Func m_func;
            ? ? ? ? void* m_handle;
            };
            typedef boost::shared_ptr DynamicSo_ptr;

            #endif

            說在最后,我在一些測試中發現有時并不自動切換到新的動態庫的情況,另一個做法就是備用兩個動態庫,那么在Reload時在兩個so文件之間切換,這樣可以確保更新,額外給自己找的好處是可以保留舊版本的so。

            久久AV高潮AV无码AV| 精品久久一区二区三区| 久久亚洲sm情趣捆绑调教| 97久久婷婷五月综合色d啪蜜芽| 亚洲狠狠婷婷综合久久蜜芽| 99久久无码一区人妻a黑| 99久久国产热无码精品免费久久久久 | 狠狠色综合网站久久久久久久高清| 亚洲乱码精品久久久久..| 久久免费精品视频| 久久久精品国产亚洲成人满18免费网站 | 亚洲国产成人久久综合区| 婷婷五月深深久久精品| 国产成人精品久久二区二区| 久久久精品久久久久特色影视| 亚洲AV无码久久| 欧美日韩中文字幕久久久不卡| 精品无码久久久久国产| 亚洲国产成人久久综合碰| 久久久久久综合一区中文字幕 | 亚洲国产另类久久久精品小说| 色综合久久天天综合| 色欲久久久天天天综合网精品| 久久最近最新中文字幕大全| 亚洲综合熟女久久久30p| 久久中文字幕视频、最近更新| 国产精品美女久久久久网| 伊人久久精品无码av一区| 色综合久久中文字幕综合网| 99久久精品九九亚洲精品| 国产精品久久久久久福利69堂| 国产成人无码精品久久久性色 | 色综合久久综合网观看| 国产精品久久久久久一区二区三区| 久久久久久免费视频| 丰满少妇高潮惨叫久久久| 午夜精品久久久久久影视riav| 91久久精品国产成人久久| 91精品国产91久久久久福利| 国产精品免费看久久久 | 久久国产高清字幕中文|