2

クライアント実行可能ファイルがリモート プロセスに挿入するサーバー ライブラリがあります。クライアントがリモート プロセスとシームレスに通信できるように、ある種の IPC/RPC 実装を設定するのはサーバーの役割です。

アップデート

次のサーバー側ヘッダーを見てください。

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
using namespace boost::interprocess;

typedef allocator<int, managed_shared_memory::segment_manager> ShmIntAllocator;
typedef vector<int, ShmIntAllocator> IntVector;

class A
{
public:
    A();
    A(string str, offset_ptr<IntVector> ints)
        : m_str(string(str)), m_ints(ints) {};
    ~A();

    string m_str;
    offset_ptr<IntVector> m_ints;
};

class B
{
public:
    B();
    B(offset_ptr<A> obj) : m_obj(obj);
    ~B();
    VOID DoSomethingUseful()
    {
        MessageBoxA(NULL, m_obj->m_str.c_str(), "SomethingUseful", MB_ICONINFORMATION);
    }

    offset_ptr<A> m_obj;
};

サーバー側の実装は次のとおりです。

managed_shared_memory g_shm;
offset_ptr<A> g_objA = nullptr;
PVOID g_hMem = nullptr;

BOOL StartServer()
    // Create a shared memory pool
    try {
        g_shm = managed_shared_memory(create_only, "MySharedMem", OVR_MAPSIZE);
    } catch(interprocess_exception& e) {
        std::string msg(e.what());
        MessageBoxA(NULL, msg.c_str(), "Error", MB_ICONERROR);
        return FALSE;
    }

    // Construct a local class instance
    const ShmIntAllocator alloc_intVector (g_shm.get_segment_manager());
    offset_ptr<IntVector> ints = g_shm.construct<IntVector>(unique_instance)(alloc_intVector);
    ints->push_back(10);
    ints->push_back(20);
    ints->push_back(30);
    g_objA = new A("Testing", ints);
    B objB(g_objA);

    // Copy data into shared memory
    size_t len = sizeof(objB); // <-- Doesn't seem to make a difference if I set this to be something higher
    g_hMem = g_shm.allocate(len);
    std::memcpy(g_hMem, &objB, len);
    return TRUE;
}

VOID StopServer()
{
    // Free used resources

    if(g_objA) {
        delete g_objA;
        g_objA = nullptr;
    }

    try{
        g_shm.destroy<B>(unique_instance);
        g_shm.deallocate(g_hMem);
        g_hMem = nullptr;
        shared_memory_object::remove("MySharedMem");
    } catch(interprocess_exception& e) {
        std::string msg(e.what());
        MessageBoxA(NULL, msg.c_str(), "Error", MB_ICONERROR);
    }
}

そしてクライアントの実装:

BOOL Connect()
{
    // Grab the shared memory pool and extract the class
    managed_shared_memory shm(open_only, "MySharedMem");
    std::pair<B*, std::size_t> ret = shm.find<B>(unique_instance); // <-- Always ends up being 0x00000000!
    B *objB = static_cast<B*>(ret.first);
    if(!objB) return FALSE;
    objB->DoSomethingUseful();
    return TRUE;
}


managed_shared_memory::find()クライアントに有効なポインターを返さない ことが常にあることに気付くでしょう。しかし、私が知る限り、コードは完全に有効です。コンパイラの警告やエラーはなく、この時点まではすべてがスムーズに実行されているようです。

では、なぜこれが失敗するのでしょうか。これを期待どおりに動作させるにはどうすればよいですか?

4

2 に答える 2

4

ポインター用の個別のアドレス空間

価値観を共有すると、すべてが明確になります。たとえば、共有メモリfloatなどに値を入れる1234.5と、反対側では簡単に読み取ることができます。

しかし、複雑なオブジェクト (ポインターを含む) を共有している場合、重要な問題があります。2 つのプロセスのアドレス空間は完全に異なり、区別されます。たとえば、プロセス1std::vectorのデータへのポインタが0x1ABF212あり、この番号はプロセス2には意味がないため、オブジェクトを共有メモリに配置することはできません。

std::vectorそのため、共有メモリに項目を 1 つずつ書き留める必要があります。複雑なデータを共有するシリアライゼーション手法について読んでください。

また、複雑なオブジェクトをプロセス間で一意のオブジェクトとして共有することを主張している場合は、特定のメモリ アロケータを使用してそれらのオブジェクトを作成できます。

AFAIKBoost.Interprocessにはそのアロケーターがあります。共有メモリを管理し、両方のプロセスにとって意味のある共有メモリ内にポインタを作成します。

あいまいでごめんなさい、私の悪い英語

于 2013-05-13T04:35:37.123 に答える
1

Unique インスタンス構築によって作成されたはずの B を見つけようとしています。ブーストのドキュメントによると

find 関数は、この「一意のインスタンス」メカニズムを使用して作成できる型 T の唯一のオブジェクトへのポインターを取得します。

しかし、あなたのコードでは、生のメモリを割り当てて、B オブジェクトをコピーするだけです。したがって、あなたの B はUnique インスタンスとして作成されませんでした

したがって、コードを次のように変更することをお勧めします。

B &objB = *g_shm.construct<B>(unique_instance) (g_objA);

それ以外の

B objB(g_objA);
于 2013-05-16T19:17:55.800 に答える