2017-07-05 10 views
1

Ich implementiert, basierend auf den Boost-Beispielen, eine ThreadSafe Queue-Klasse im Shared Memory. Es funktioniert wie erwartet für ein einfaches Produzenten/Verbraucher-Modell. Als nächsten Schritt habe ich die Schnittstelle IConcurrentIPCQueue definiert, die von der Klasse ConcurrentIPCQueue implementiert wird. Ich brauche die Schnittstelle, damit ich einen Adapter zu der Warteschlange für ein anderes Problem implementieren kann.Lesezugriffsverletzung beim Zugriff auf freigegebenen Speicher

Der einzige Unterschied zwischen meiner ersten Version und dem aktuellen unten ist die folgende:

Erste Version:

template <class T> class ConcurrentIPCQueue 

nun die Informationen hinzufügen, dass ich die Schnittstelle so implementieren möchten :

Aktuelle Version:

`template <class T> class ConcurrentIPCQueue :public IConcurrentIPCQueue<T>` 

führt zu einer Lesezugriffsverletzung auf der Verbraucherseite. Auf der Herstellerseite kann ich einfach push_back und pop_front Daten richtig für sich selbst. Aber komischerweise kann ich nicht auf den Shared Memory zugreifen (obwohl das Paar aus segment.find eine Adresse und 1) korrekt zurückgibt. Die Frage ist also, warum die Version mit der Implementierung der Schnittstelle auf der Verbraucherseite einen Unterschied macht und zu diesem seltsamen Fehler führt. Und wie kann ich es lösen?

das Beispiel kurz zu halten, stelle ich hier ein minimalistisches Modell der Warteschlange:

#include <boost/interprocess/allocators/allocator.hpp> 
#include <boost/interprocess/containers/deque.hpp> 
#include <boost/interprocess/managed_shared_memory.hpp> 
#include <boost/interprocess/sync/interprocess_condition.hpp> 
#include <boost/interprocess/sync/interprocess_mutex.hpp> 
#include <boost/thread/lock_guard.hpp> 
#include <sstream> 

namespace boost_ipc = boost::interprocess; 
static char const *SHMEMNAME= "SHMEM"; 
static char const *SHQUEUENAME= "MYQUEUE"; 

template <class T> class IConcurrentIPCQueue 
{ 
public: 
    virtual void push_back(T const & data) = 0; 
    virtual bool pop_front(T & data) = 0; 
virtual unsigned int size() = 0; 
}; 

template <class T> class ConcurrentIPCQueue :public IConcurrentIPCQueue<T> 
{ 
public: 
    // allocator for allocating memory from the shared memory 
    typedef boost_ipc::allocator<T, boost_ipc::managed_shared_memory::segment_manager> ShmemAlloc; 
    typedef boost_ipc::interprocess_mutex IPC_Mutex; 
    typedef boost_ipc::interprocess_condition IPC_Cond; 
    typedef boost::lock_guard<IPC_Mutex> LockGuard; 

    ConcurrentIPCQueue(ShmemAlloc salloc) : mQueue_(salloc) { } 

    void push_back(T const & data) 
    { 
     { 
      LockGuard lock(mMutex_); 
      mQueue_.push_back(data); 
     } 
     mWait_.notify_one(); 
    } 

    bool pop_front(T & data) 
    { 
     LockGuard lock(mMutex_); 

     if (mQueue_.empty()) 
      return false; 

     data = mQueue_.front(); // return reference to first element 
     mQueue_.pop_front(); // remove the first element 

     return true; 
    } 

unsigned int size() 
{ 
    LockGuard lock(mMutex_); 
    return mQueue_.size(); 
} 

private: 
    boost_ipc::deque<T, ShmemAlloc> mQueue_; 
    IPC_Mutex mMutex_; 
    IPC_Cond mWait_; 
}; 

typedef ConcurrentIPCQueue<char> myqueue; 

void consumer() 
{ 
    boost_ipc::managed_shared_memory openedSegment(boost_ipc::open_only, SHMEMNAME); 

    myqueue*openedQueue = openedSegment.find<myqueue>(SHQUEUENAME).first; 
    char tmp; 

    while (openedQueue->pop_front(tmp)) { 
     std::cout << "Received " << tmp << "\n"; 
    } 
} 

void producer() { 
    boost_ipc::shared_memory_object::remove(SHMEMNAME); 

    boost_ipc::managed_shared_memory mysegment(boost_ipc::create_only, SHMEMNAME, 131072); 

    myqueue::ShmemAlloc alloc(mysegment.get_segment_manager()); 
    myqueue*myQueue = mysegment.construct<myqueue>(SHQUEUENAME)(alloc); 
char mychar='A'; 

    for (int i = 0; i < 10; ++i) 
     myQueue->push_back(mychar); 

    while (myQueue->size() > 0) 
     continue; 
} 

int main() 
{ 
    //producer(); // delete comment for creating producer process 
    consumer(); 
    return 0; 
} 
+0

warum haben Sie Ihre String-Konstanten zweimal definiert? Können Sie ein komplettes ausführbares Programm bereitstellen? – didierc

+0

ok, das war ein Fehler bei der Erstellung dieses minimalistischen Modells. Ich löschte es und fügte eine main-function() hinzu, wo man in der Funktion entweder für den Producer() oder den Consumer() –

Antwort

1

UPDATE:

ich es mit MSVC15.3 und 1,64 Erhöhung reproduzieren konnten.

Es stellt sich heraus, dass die Vtable-Zeiger das Problem sind: Sie sind in jedem Prozess unterschiedlich, was zu Undefined Behavior führt, sobald Sie polymorphe Laufzeittypen() haben.

Es stellt sich heraus die Dokumentation verbietet es klar: Is it possible to store polymorphic class in shared memory?

+0

kommentieren muss, das ist wirklich seltsam, dass es für dich funktioniert. Warum macht es sogar einen Unterschied, wenn ich von der Schnittstelle erben und wann nicht. Ich erhöhte in VS von Hand die Stack- und Heap-Größen, die anfängliche virtuelle Speichergröße auf Windows, erhöhte die "Reserve" -Größe wie Sie im Code, aber es funktioniert immer noch nicht (außer ich erben nicht von der Schnittstelle). Kann es vielleicht auch ein anderes Problem sein? –

+0

Stellen Sie sicher, dass Ihr Codebeispiel das Problem veranschaulicht. Jetzt weiß ich nicht einmal, was Sie mit "Ich erben nicht von der Schnittstelle" meinen. – sehe

+0

Ich habe versucht, mein Problem besser zu erklären, ich hoffe, dass es jetzt 0nerstandbar ist –

Verwandte Themen