Boost Interprocess named_mutex导致分段错误

时间:2018-05-30 15:18:20

标签: c++ memory-management boost shared-memory boost-interprocess

我正在使用boost进程来共享内存,但是当我尝试使用boost :: interprocess :: scoped_lock尝试使用boost :: interprocess:named_mutex时很少出现分段错误。

我只运行编写程序进程。此进程拥有共享内存并且不会销毁它(除非应用程序正在关闭)。应用程序使用SharedDataCommon类(参见问题的底部)创建共享内存,该类包含所有boost内部工作,然后我调用write(),它尝试检索named_mutex但是它会出错。

分段错误发生在

  

升压/间/同步/ POSIX / named_semaphore.hpp

第63行:

void wait()
   {  semaphore_wait(mp_sem); }     // seg faults here

就好像有人在应用程序运行时更改了对信号量的权限,但他们没有。是否有一个日志来检查在分段错误之前是否更改了权限?

在写入之前执行范围锁定时发生分段错误:

bool write(const std::vector<T>& vec, const bool clearFirst = false)
{
    bip::scoped_lock<bip::named_mutex> lock(*sdc.mutex);   // seg faults here

    try
    {
        sdc.vec->reserve(sdc.vec->size() + vec.size());
    }
    catch(std::exception& e)
    {
        std::cout << "Not enough room to write elements" << std::endl;
        return false;
    }

    if(clearFirst)
    {
        sdc.vec->clear();
    }

    for(const auto& item : vec)
    {
        sdc.vec->push_back(item);
    }

    sdc.cond_empty->notify_all();

    return true;
} 

sdc是一个封装boost :: interprocess组件的SharedDataCommon实例(见下文)。

我设置了临时设置umask,以便多个Linux用户可以读取共享内存。

template<typename T>
struct SharedDataCommon
{
    using ShmemAllocator = bip::allocator<T, bip::managed_shared_memory::segment_manager>;
    using MyVector = bip::vector<T, ShmemAllocator>;

    void initialise(const std::string& tag, const int numBytes, const bool ownMemory)
    {
        const std::string sharedMemoryName = tag + "_shared_memory";
        const std::string sharedVectorName = tag + "_shared_vector";
        const std::string sharedMutexName = tag + "_shared_mutex";
        const std::string sharedCVName = tag + "_shared_cv";

        tag_name = tag;
        shared_memory_name = sharedMemoryName;
        shared_mutex_name = sharedMutexName;
        shared_vector_name = sharedVectorName;
        shared_cv_name = sharedCVName;
        destroy_memory = ownMemory;

        if(ownMemory)
        {
            destroyMemory(tag);
        }

        createMemory(numBytes);
    }

    void createMemory(const int numBytes)
    {
        const mode_t old_umask = umask(0);

        bip::permissions perm;
        perm.set_unrestricted();
        segment.reset(new bip::managed_shared_memory(bip::open_or_create, shared_memory_name.c_str(), numBytes, 0, perm));

        mutex.reset(new bip::named_mutex(bip::open_or_create, shared_mutex_name.c_str(), perm));

        const ShmemAllocator alloc_inst(segment->get_segment_manager());
        vec = segment->find_or_construct<MyVector>(shared_vector_name.c_str())(alloc_inst);

        cond_empty.reset(new bip::named_condition(bip::open_or_create, shared_cv_name.c_str(), perm));

        umask(old_umask);
    }

    static void destroyMemory(const std::string& tag)
    {
        const std::string sharedMemoryName = tag + "_shared_memory";
        const std::string sharedMutexName = tag + "_shared_mutex";
        const std::string sharedCVName = tag + "_shared_cv";

        bip::named_mutex::remove(sharedMutexName.c_str());
        bip::named_condition::remove(sharedCVName.c_str());     
        bip::shared_memory_object::remove(sharedMemoryName.c_str());
    }

    ~SharedDataCommon()
    {
        if(destroy_memory)
        {
            destroyMemory(tag_name);
        }
    }

    std::shared_ptr<bip::named_mutex>           mutex{nullptr};
    MyVector*                                   vec{nullptr};
    std::shared_ptr<bip::managed_shared_memory> segment{nullptr};
    std::shared_ptr<bip::named_condition>       cond_empty;
    bool                                        destroy_memory{false};
    std::string                                 shared_vector_name;
    std::string                                 shared_mutex_name;
    std::string                                 shared_cv_name;
    std::string                                 shared_memory_name;
    std::string                                 tag_name;
};

我没有看到任何解释为什么问题会在某些时候发生的原因?

1 个答案:

答案 0 :(得分:0)

当您可以在共享内存段中使用未命名的进程间同步原语时,为什么要使用所有这些单独的命名实体?参见例如Boost Interprocess share memory deletion, permissions and output files(第二个例子)。

这会立即消除检索所有共享对象和实际同步基元之间的竞争条件。

我唯一可以合理地看到在共享对象之外的是named_mutex,因此您可以同步实际创建共享内存段。但是,看看你的代码看起来你没有做到这一点:

    segment.reset(new bip::managed_shared_memory(bip::open_or_create, shared_memory_name.c_str(), numBytes, 0, perm));

    mutex.reset(new bip::named_mutex(bip::open_or_create, shared_mutex_name.c_str(), perm));

在段之后创建互斥锁。现在,当您控制服务器和客户端启动的顺序时,这可能不是问题。但是,在这种情况下,显然不需要存在单独的命名互斥体。

同样令人担心的是你在没有任何同步的情况下破坏内存:

destroyMemory(tag);