访问共享内存时读取访问冲突

时间:2017-07-05 11:09:12

标签: c++ boost segmentation-fault ipc shared-memory

我基于boost示例实现了共享内存中的线程安全队列类。它对预期的简单生产者/消费者模型起作用。

下一步,我定义了由IConcurrentIPCQueue类实现的接口ConcurrentIPCQueue。我需要接口,所以我可以为队列实现适配器以解决另一个问题。

我的第一个版本和下面的当前版本之间的唯一区别如下:

第一个版本:

template <class T> class ConcurrentIPCQueue

现在添加信息,我想实现这样的界面:

当前版本:

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

导致消费者端的读取访问冲突。在制作人方面,我可以轻松地自己push_backpop_front数据。但奇怪的是在消费者方面,我无法访问共享内存(尽管来自segment.find的对正确返回一个地址和1)。 所以问题是,为什么实现接口的版本会在消费者方面产生影响并导致这种奇怪的错误。我怎么解决它?

为了简化示例,我在这里介绍了队列的简约模型:

#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;
}

1 个答案:

答案 0 :(得分:1)

更新:

我可以用MSVC15.3和Boost 1.64重现它。

事实证明vtable指针是个问题:它们在每个进程中都是不同的,只要你有运行时多态类型(std::is_polymorphic<T>)就会导致未定义的行为。

事实证明,文档明确禁止它:Is it possible to store polymorphic class in shared memory?