2014-06-27 148 views
4

對於那些熟悉進程間通信的人,我有一個快速的問題。通過內存共享C++對象

形勢

  • 我有一個計劃(方案一),我可以添加一些代碼,但非常有限。這是生成大量數據的主要程序。
  • 數據的表達方式是有限的,所以我想創建第二個程序(程序B),因此需要從A到B獲取數據。甚至有時會導致A運行一些沒有返回值的函數。
  • 我知道命名管道,但我覺得他們可能會體積龐大? - 不知道 - 我有例如以下問題(可能沒有根據):
    1. 數據流=>轉換爲二進制 - >將數據放在內存中 - >服務器讀取 - >轉換爲字符串 - >通過可能是一個開關語句確定請求 - >獲取請求 - >轉換爲二進制 - >在內存中放置 - >由客戶端讀取並轉換爲字符串/一些可接受的格式。
    2. 它必須基本上使用雙方的開關語句,如果你想要一個不同於字符串的信息格式,你需要考慮這一點
    3. 一條消息可能要等待另一條消息完成,所以它在同一時間的很多電話中可能會更慢? - 不確定
  • 其他進程間通信方法可能有同樣的問題。
  • 更好的解決方案我認爲會創建一個「對象」類。與程序之間共享對象的內存地址,從而在理論上「合併」 A和B,則:

    1. 沒有與編碼和解碼的問題等
    2. 數據只是要求沒有問題/通過調用一個函數調用。
    3. 函數返回正確的類型,也不需要建立正確的類型是什麼(即布爾/ INT /串/雙等)

    我明白,這也有幾個問題,即,如果對象被刪除從內存位置由主/另一個程序訪問它。

問題

  • 什麼是解決這一問題的最佳途徑:
  • 是否有在C++中調用的選項,讓我寫和從存儲器地址讀?此刻:
    1. 我可以訪問A和B之間的同一個對象,但是我不能寫/讀,因爲這會拋出異常。那麼基本上我可以通過簡單的調用或者讀寫這個對象嗎?
    2. 我知道WriteProcessMemory函數 - 但這不是我想要的 - 即我不一定要更改內存值,只是訪問數據/調用B將執行的操作。
  • 有沒有一個簡單而簡單的方法呢?我知道一些叫做boost的東西,但是對它不瞭解 - 這是我最好的選擇嗎? - >即我應該調查這是我最好的解決方案嗎?

非常感謝您對此問題的任何建議。

+0

*「我知道一些叫做boost的東西」*。好。但最好的辦法是使用它:http://boost.org。而且......驚喜!有些東西可以幫助你解決問題:[Boost.Interprocess](http://www.boost.org/doc/libs/1_55_0/doc/html/interprocess.html) –

+0

你可以通過管道發送二進制數據就好了。實際上,對於操作系統而言,通過管道的東西是一個原始的字節流。但是你想使用正確的序列化格式。 「Cap'n Proto」如何對您的情況有好處,那麼線格式與內存中的數據相同。 – datenwolf

回答

1

Boost.Interprocess有許多方法來共享進程之間的數據,其中之一是從升壓,其中一個程序充當服務器或客戶端爲相同的存儲對象(根據參數值是否給出或採取shared_memory

示例不)

include <boost/interprocess/shared_memory_object.hpp> 
#include <boost/interprocess/mapped_region.hpp> 
#include <cstring> 
#include <cstdlib> 
#include <string> 

int main(int argc, char *argv[]) 
{ 
    using namespace boost::interprocess; 

    if(argc == 1){ //Parent process 
     //Remove shared memory on construction and destruction 
     struct shm_remove 
     { 
     shm_remove() { shared_memory_object::remove("MySharedMemory"); } 
     ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } 
     } remover; 

     //Create a shared memory object. 
     shared_memory_object shm (create_only, "MySharedMemory", read_write); 

     //Set size 
     shm.truncate(1000); 

     //Map the whole shared memory in this process 
     mapped_region region(shm, read_write); 

     //Write all the memory to 1 
     std::memset(region.get_address(), 1, region.get_size()); 

     //Launch child process 
     std::string s(argv[0]); s += " child "; 
     if(0 != std::system(s.c_str())) 
     return 1; 
    } 
    else{ 
     //Open already created shared memory object. 
     shared_memory_object shm (open_only, "MySharedMemory", read_only); 

     //Map the whole shared memory in this process 
     mapped_region region(shm, read_only); 

     //Check that memory was initialized to 1 
     char *mem = static_cast<char*>(region.get_address()); 
     for(std::size_t i = 0; i < region.get_size(); ++i) 
     if(*mem++ != 1) 
      return 1; //Error checking memory 
    } 
    return 0; 
} 
+0

感謝彼得。我會試試這個。我之前沒有做過共享記憶。我的想法是正確的,你可以放置一個對象在共享內存位置,並提供A和B都有一個對象構造的「原型」 - 即兩個引用相同的類,並只在兩邊創建指針,你可以使用它?還是更像是「命名管道」,在這裏命名內存,A和B都監視共享內存的變化。我認爲這是前者。我會進一步調查Boost。謝謝!!!! – DaClan

+2

@DaClan可以在共享內存中創建類,但您必須小心同步問題,請查看http://www.boost.org/doc/libs/1_55_0/doc/html/interprocess/managed_memory_segments .html#interprocess.managed_memory_segments.managed_memory_segment_features.allocation_types(更好的是,花一些時間來閱讀整個Interprocess文檔,這不是一件容易的事情) – Pieter

+0

感謝Pieter,這將有很大的幫助! – DaClan

1

簡化!

一般來說,shared state可能是一個壞主意,不會很好測試,並可能會造成無法管理的體系結構的浩劫,因爲global variables可以做到。

ØMQ guide可能會幫助您掌握可能的解決方案。一般來說,如果您沒有特殊要求,請使用消息傳遞。 ØMQ「套接字」是快速的,相當健壯的,並且需要很少的代碼才能入門。

更新:成衣:msgpack-rpcprotobuf-remote

+0

謝謝@Dmitry。我知道這個解決方案。但是除非我弄錯了,否則你仍然坐在一個編碼和解碼的問題上,因爲有100個函數需要調用,所以你必須確定哪個函數實際上被髮送的消息調用了 - 我已經開始了一個與之前的命名管道相似的根,但編碼看起來很麻煩,因爲您需要在服務器和客戶端編寫編碼和解碼功能。這可能是簡單的解決方案!但是,編寫它的性能/效率是否很快? - 共享課堂不是更好的解決方案嗎? – DaClan

+0

有簡單的解決方案:RPC:[msgpack-rpc](https:// github。com/msgpack-rpc/msgpack-rpc-cpp)或[protobuf-remote](https://code.google.com/p/protobuf-remote/wiki/GettingStartedCpp) –

+0

,將您不需要的問題妥善分離編程和解碼功能。您的接口的聲明將同時用於編碼和解碼的實現,並且C++代碼 –

0

你在做一個軟件客戶,或者只是爲自己進行數據分析?如果僅僅爲了您自己,您可以將數據寫入硬盤,並將分析分爲兩步。

+0

這是一個測試項目。如果可能的話可以出售。主要是爲我工作的財務公司。程序A是第三方程序,允許C++代碼被添加到有限的範圍內。在硬盤上寫入所有數據實在太多了。程序A具有大約100個主要在另一個位置調用服務器的功能(即,存儲在異地的數據)。我已經要求提供一個API函數,但是它們是直接訪問我的。因此,程序A與服務器C進行會談以複製所有數據,不幸的是無法工作。 – DaClan

+0

Ps。獲得這些數據有一些關鍵的時間影響。所以我的解決方案必須易於實現(即不要使用消息傳遞,因爲這需要兩次編寫每個函數 - 一次用於消息 - 另一個用於解碼側以瞭解應該調用哪個函數)並且很快。 – DaClan

+0

@DaClan我對進程間通信不是很熟悉。怎麼樣使用TCP連接?您可以將您的程序作爲服務器,並以程序A的身份作爲客戶端。 – jiandingzhe