2017-09-13 46 views
0

我有一個使用單身的程序。該程序在運行時加載共享對象庫。這個庫也使用同一個單例。 問題是,當從庫中訪問單例時,將創建單例的新實例。運行時動態加載和單身人士

程序與-rdynamic聯繫,我用-fPIC兩個和裝載情況是這樣的:

std::shared_ptr<Module> createModuleObject(const std::string& filename) 
{ 
    if (!fs::exists(filename)) 
     throw std::runtime_error("Library not found: " + std::string(filename)); 

    struct export_vtable* imports; 
    void *handle = dlopen(filename.c_str(), RTLD_LAZY | RTLD_GLOBAL); 

    if (handle) { 
     imports = static_cast<export_vtable*>(dlsym(handle, "exports")); 
     if (imports) 
      return std::shared_ptr<Module>(imports->make()); 
     else 
      throw std::runtime_error("Error trying to find exported function in library!"); 
    } else 
     throw std::runtime_error("Error trying to load library: " + std::string(filename)); 
} 

的庫導出這樣的類:

Module* make_instance() 
{ 
    return new HelloWorld(); 
} 
struct export_vtable 
{ 
    Module* (*make)(void); 
}; 
struct export_vtable exports = { make_instance }; 

和類利用的單身人士。

這是怎樣的單創建(Configuration.cpp):

std::unique_ptr<Configuration> Configuration::instance_(nullptr); 
std::once_flag Configuration::onlyOnceFlag_; 

Configuration& Configuration::instance() 
{ 
    if (instance_ == nullptr) 
    { 
     std::cout << "INSTANCE IS NULL, CREATING NEW ONE" << std::endl; 
     std::call_once(Configuration::onlyOnceFlag_, 
        [] { 
          Configuration::instance_.reset(new Configuration()); 
         }); 
    } 

    return *Configuration::instance_; 
}  

兩個程序,對Configuration.cpp庫鏈接。如果我從庫中省略,嘗試訪問單例時遇到未定義的符號錯誤。

任何人都知道如何解決這個問題?非常感謝你!

+1

這就是爲什麼單身是一個壞主意的原因之一。它們不能像動態鏈接庫那樣按預期工作。還相當堅持[斯科特邁耶的Singleton模式](https://stackoverflow.com/questions/1008019/c-singleton-design-pattern)。 – user0042

+0

單身沒什麼問題。這個特定的實現有兩個問題:1)你放棄了對單身生命的控制。首次調用獲取實例方法創建單例從來都不是一個好主意。 2)你的庫創建它自己的單例,而不是請求由父應用程序創建的單例。爲了解決這個'instance()'方法應該從主應用程序導入。附:斯科特邁耶的單身模式應該被稱爲反模式。 – VTT

+0

應該有可能重用庫中的同一個單例,但不是嗎?問題似乎是圖書館內部的單身人士隱瞞另一人。 有一個'setConfiguration()'方法或庫中的某些東西對我來說也不是一種選擇,因爲它有點違背了目的。 **編輯:**你是什麼意思的「從主應用程序導入」? – Pfaeff

回答

0

下面是我如何解決它的https://github.com/kvahed/codeare/blob/master/src/core/ReconStrategy.hpp 在加載共享對象後,我將全局單例的實例Workspace分配給dll中的加載類。 https://github.com/kvahed/codeare/tree/master/src/modules中的所有課程均源自ReconStrategy以及共享對象。好的是這個代碼是可移植的。

在構建這樣的ReconStrategy發生這種情況:

ReconContext::ReconContext (const char* name) { 
    m_dlib = LoadModule ((char*)name); 
    if (m_dlib) { 
    create_t* create = (create_t*) GetFunction (m_dlib, (char*)"create"); 
    m_strategy = create(); 
    m_strategy->Name (name); 
    m_strategy->WSpace (&Workspace::Instance()); 
    } else { 
     m_strategy = 0; 
    } 
    } 
} 

重點線這裏是m_strategy->WSpace (&Workspace::Instance());

+0

只要你有第二個單身試圖訪問第一個單身人士(例如記錄單身人士),就停止工作。那麼你也必須有一個分配方法。它有點擊敗了目的。 – Pfaeff

+0

可以請有人採取一秒鐘等待迴應之前投票的意思是幫助。我永遠不會明白這個動機來自何處。我只能投下惡意和嚴重疏忽。 這是valgrind測試代碼,整天運行在沒有內存泄漏的MRI機器上。我上面提供的內容允許每個共享對象擁有私有矩陣的本地工作空間,重建服務的全局可以將其傳遞到鏈中的重建步驟。 說真的,我不會得到一些人。 –

+0

所以你會將單個工作區對象中的所有單例組合起來,然後將其分配給您的庫?如果單身人士需要彼此訪問呢?我們假設一個日誌單身試圖從配置單身人士確定日誌級別 – Pfaeff