2011-01-06 236 views
9

我在想如何在不同的程序模塊之間共享一些內存 - 可以說,我有一個主應用程序(exe),然後是一些模塊(dll)。它們都鏈接到相同的靜態庫。這個靜態庫將有一些經理,提供各種服務。我想實現的目標是讓所有應用程序模塊之間共享此管理器,並在庫初始化期間透明地執行此操作。 在進程之間我可以使用共享內存,但是我只想在當前進程中共享這個進程。 你能想到一些跨平臺的方式來做到這一點?可能使用boost庫,如果他們提供一些設施來做到這一點。在模塊之間共享內存

我現在唯一能想到的解決方案是使用相應操作系統的共享庫,所有其他模塊將在運行時鏈接到該庫,並將管理器保存到那裏。

編輯: 爲了澄清什麼,我真的需要:

  1. 我需要找出,如果共享經理已經創建(答案已經在下面提供了一些方法來做到這一點)
  2. 獲取指向管理器的指針(如果存在),或將指針設置爲新創建的管理器對象的某處。
+0

鑑於這是一個單獨的過程,這與普通的單例模式有什麼不同? – sdg 2011-01-06 14:56:27

+0

它實際上是一個單身人士,問題是如何實現它,所以它會在不同的共享庫之間共享。 – 2011-01-06 15:05:36

+0

在同一個進程中,任何模塊都可以不受任何限制地訪問外部全局變量。 – 9dan 2011-01-06 15:09:28

回答

11

我認爲你需要共享庫的幫助才能以任何便攜的方式做到這一點。它不一定需要知道任何關於模塊之間共享的對象,它只需要提供一些全局可訪問的映射,從一個鍵(可能是一個字符串)到一個指針。但是,如果你願意調用操作系統API,這是可行的,我想你可能只需要兩個操作系統特定部分的實現(一個用於Windows DLL和GetProcAddress,一個用於使用dlopen的操作系統) 。

隨着每個模塊的加載,它將遍歷之前加載的模塊列表,查找任何導出特定函數的模塊。如果它找到一個(任何,無關緊要,因爲不變是所有完全加載的模塊都知道該公共對象),它從先前加載的模塊獲取公共對象的地址,然後增加引用計數。如果無法找到,則分配新數據並初始化引用計數。在模塊卸載期間,如果引用計數達到零,它將遞減引用計數並釋放公共對象。

當然,對於通用對象使用操作系統分配器是很有必要的,因爲雖然不太可能,但它有可能從與第一次加載的庫不同的庫中分配。這也意味着公共對象不能包含任何虛擬函數或任何其他類型的指向不同模塊段的指針。其所有資源必須通過使用OS進程範圍分配器動態分配。對於libC++是共享庫的系統來說,這可能不是一個負擔,但是你說你正在靜態鏈接CRT。

功能在Win32中需要將包括EnumProcessModulesGetProcAddressHeapAllocHeapFreeGetProcessHeapGetCurrentProcess。我認爲我會堅持把通用對象放在它自己的共享庫中,這會利用加載器的數據結構來找到它。否則,你正在重新發明裝載機。即使CRT靜態鏈接到幾個模塊中,這也可以工作,但我認爲你正在設置自己的ODR違規。確實需要保持公共數據POD。

1

從當前過程而已,你不使用不需要設計任何特殊的功能或結構。

即使沒有任何功能,您也可以這樣做,但它更安全並且跨平臺友好來定義提供訪問共享數據的功能集。這些功能可以通過常用的靜態庫來實現。

我想,只有這個設置的問題是:「誰會擁有這些數據?」。共享數據必須存在且只有一個所有者。

有了這些基本概念,我們可以勾畫API這樣的:

IsSharedDataExist  // check whether of not shared data exist 

CreateSharedData  // create (possibly dynamically) shared data 

DestroySharedData  // destroy shared data 

... various data access API ... 

或C++與Singleton模式的類將是適當的。


UPDATE

我很困惑。真正的問題可以定義爲「如何在一個靜態庫中實現一個Singleton類,它將以多個動態加載庫(將在同一個進程中使用)以獨立於平臺的方式鏈接」。

我認爲,基本的想法並沒有太大的不同,但要確保單身是真正的單身是這種設置的額外問題。

爲此,您可以使用Boost.Interprocess。

#include <boost/config.hpp> 
#include <boost/interprocess/sync/named_mutex.hpp> 
... 
boost::interprocess::named_mutex* singleton_check = 0; 

// in the Create function of the singleton 
try { 
    singleton_check = new boost::interprocess::named_mutex(boost::interprocess::create_only, "name_of_the_mutex"); 
    // if no exception throw, this is the first time execution 
} 
catch (...) 
{ 
} 

釋放named_mutex與delete singleton_check一樣簡單。


更新#2

另一項建議。

我想,我們不應該在共同的靜態庫中放置共享數據。如果我們無法確保全球獨一無二的數據,那麼這不僅是棘手的平臺依賴性實施問題,還會浪費內存和全球資源。

如果你更喜歡靜態庫實現,你應該創建兩個靜態庫。一個用於共享數據的服務器/創建者,一個用於該共享數據的用戶。服務器庫定義並提供對Singleton的訪問。客戶端庫提供各種數據訪問方法。

這與沒有靜態庫的Singleton實現完全相同。

0

MSDN我看到有兩條途徑模塊

  1. 使用data_seg雜注
  2. 使用共享內存之間的數據共享。

正如有人指出共享段只適用於同一dll的兩個實例,所以我們只剩下一個選擇使用內存映射文件技術。