2016-12-29 78 views
1

我在C++中有一個應用程序,它通過共享對象從兩個或多個插件(每個插件至少有一個線程)加載其大部分代碼。我用下面的代碼加載插件:在C++中,其他兩個不同的共享對象可以從第三個共享對象訪問Singleton嗎?

pluginHandle = dlopen(fileName, RTLD_NOW|RTLD_GLOBAL); 
init_t* init = (init_t*) dlsym(pluginHandle, "init") // Create should return an instance of the class of the plugin 
plugin = init(); 

我到達的地步,我需要兩個那些插件來開始將數據添加到一個共同的Queue。由於應用程序不允許在不改變應用程序本身中的代碼的情況下在兩個插件之間進行通信(我們試圖避免的一點),所以我想我找到了解決這個問題的方法:第三個插件,其中包括一個帶有線程安全的Queue

然後,我會重新編譯和鏈接兩個插件庫,並使用getInstance()獲取單身人士,並開始添加任務到隊列。

這是一個安全的實現嗎?單身人士Queue會工作嗎?

回答

1

一個動態庫(共享對象),它包含一個具有線程安全隊列的單例類。

當你想約束一個類只被實例化一次時,使用單例。這就是而不是你想要什麼:你想讓你所有的插件在一個類的特定實例上工作。這裏沒有「只有一個人可以生活」的要求。

在C++ 11線程安全使用單邁耶的模式可能看起來像這樣:

class Singleton 
{ 
private: 
    Singleton(); 

public: 
    Singleton(const &Singleton) = delete; 
    Singleton& operator=(const &Singleton) = delete; 

    static Singleton& get_instance() 
    { 
     static Singleton s; 
     return s; 
    } 
}; 

默認構造方法聲明爲private和複製/賦值操作都將被刪除,以避免多個實例。

你需要更簡單的東西:一個函數總是返回相同的實例。事情是這樣的:

class Manager 
{ 
public: 
    static Resource& get_resource() 
    { 
     static Resource r; 
     return r; 
    } 
}; 

沒有必要,以防止多個實例:如果你想同一個實例,只問了相同的實例。

您也可以與資源池返回給一些ID的同一實例擴展設計:

enum class ResourceId 
{ 
    ID_FOR_A_FAMILY_OF_PLUGIN, 
    ID_FOR_AN_OTHER_FAMILY_OF_PLUGIN 
}; 

class Pool 
{ 
public: 
    static Resource& get_resource(ResourceId id) 
    { 
     static std::map<ResourceId, Resource> p; 
     return p[id]; 
    } 
}; 

注意,在這個例子中p[id]是與Resource的默認構造函數動態創建。您可能需要在施工期間傳遞參數:

class Resource 
{ 
public: 
    Resource():ready(false){} 

    void init(some parameters) 
    { 
     // do some intialization 
     ready = true; 
    } 

    bool is_ready() const { return ready; } 

private: 
    bool ready; 
}; 

class Pool 
{ 
public: 
    static Resource& get_resource(ResourceId id) 
    { 
     static std::map<ResourceId, Resource> p; 
     auto& r = p[id]; 
     if(!r.is_ready()) 
     { 
      r.init(some parameters); 
     } 
     return r; 
    } 
}; 

或者,使用指針,允許多態性

class Pool 
{ 
public: 
    static std::unique_ptr<Resource>& get_resource(ResourceId id) 
    { 
     static std::map<ResourceId, std::unique_ptr<Resource>> p; 
     auto& r = p[id]; 
     if(!r) 
     { 
      r = std::make_unique<SomeResourceTypeForId>(some parameters); 
     } 
     return r; 
    } 
}; 

注意的是,過去兩年實現需要周圍的非靜態代碼互斥是thread-安全。