2011-11-29 132 views
3

我使用shmget分配了一塊共享內存。共享內存進程間通信

然後,我使用shmat分別將共享內存附加到進程A和進程B.我假設由shmat返回的A和B的句柄(即A和B內映射到實際共享內存的地址)是不同的。

我們假設A和B的手柄分別定義爲char* pchar* q。 我的問題是如果我們在進程A中寫入一個對象到地址p + sizeof(anotherObject),我們可以期望在進程B中的地址q + sizeof(anotherObject)處獲得相同的對象嗎?

我想是這樣,但並非100%確定。如果是這樣,這個通信或映射機制是如何實現的,因爲我們知道p + sizeof(anotherObject)q + sizeof(anotherObject)指的是不同的內存位置?

+0

考慮使用Boost.Interprocess - 有一個文檔可以回答像你這樣的問題。 – Simon

+0

考慮使用現代接口'shm_open'和'mmap'來完成這樣的任務。他們限制較少,更容易處理。 –

回答

4

現代處理器使用虛擬地址空間。您在程序中使用的地址不是對象的「真實」地址,操作系統和處理器將內存頁面映射到地址範圍,並將其用作「內存」。

創建共享內存僅僅意味着操作系統將同一內存頁映射到兩個或更多不同進程的地址空間。兩個進程中的兩個指針不具有相同數值的事實意味着什麼,即使不同進程中的指針具有相同的數值,它們通常也指向不同的內存位置。

關於將「對象」寫入內存,首先必須「序列化」它。我提到了不同進程中的指針彼此不兼容。如果你的對象有任何指針成員或其他可能包含指針的對象,你必須想出一種方法來將這些指針替換爲實際數據,因爲一旦你從另一個線程讀取對象,那些指針就會像垃圾。

請注意,C++ std :: sting,std :: vector和其他容器以及任何虛擬對象(具有虛函數的對象)都有指針。所以如果你想傳遞一個字符串,你需要將它作爲一個字符序列寫入共享內存中,並在另一側以相同的方式讀取。

+0

+1對我的理解非常有幫助。 –

0

你能寫共享內存區域中的對象的二進制表示嗎?是。

您是否可以通過訪問存儲在共享內存中的二進制表示形式安全地使用另一個程序中的對象?有時候,但不一般。

這些規則類似於將串行化的二進制表示寫出到磁盤或通過線路。您必須確保處理指向其他對象的指針以及所有非POD成員。例如,std::string實例有一個指針指向分配的存儲器,其中:

  1. 可能不是在共享存儲器中的區域
  2. 可能沒有在其他過程中的相同的地址(例如,該數據是在共享存儲器中,但共享內存區域在兩個進程中映射到不同的基址)。

於是,一種簡單的規則是:如果X是什麼,你不能:

std::ofstream file("foo.bin",std::ios::binary); 
file.write(reinterpret_cast<const char*>(&X), sizeof(X)); 

那麼你不能安全地寫出來到共享內存中。

備註:即使數據是POD類型,也不能認爲寫出它是安全的。在某些操作系統上,可以運行幾種不同類型的進程(例如32位和64位進程)。在這種情況下,使用類型如int可能在兩個過程中都不相同。給定一個特定的操作系統,一個特定的編譯器和特定的編譯設置,就有可能推導出一種可靠的方式來編寫這種POD類型。如果這個環境可以改變,就避免像瘟疫那樣做。

+0

您可以使用固定寬度的POD(如int32_t和uint8_t)來確保32位和64位進程都可以使用它們。 – 2011-11-29 22:07:11

+0

@WTP:仍不能保證兩個進程都使用相同的編譯器和相同的對齊方式。這比看起來更微妙。因此,實現這一點*可能*,但不*保證*。 –