简体   繁体   中英

Boost Interprocess named_mutex causing segmentation fault

I'm using boost interprocess to share memory but very rarely getting a segmentation fault when I try to take a boost::interprocess:named_mutex using boost::interprocess::scoped_lock.

I am only running the writer process. This process owns the shared memory and does not destroy it (unless the application is closing down). The application creates the shared memory using SharedDataCommon class (see bottom of question) which encpsulates all the boost inner workings and then later on I call write(), which tries to retrieves the named_mutex but it seg faults.

The segmentation fault occurs within

boost/interprocess/sync/posix/named_semaphore.hpp

line 63:

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

It's as if someone changes the permissions to the semaphore whilst the application is running, except they didn't. Is there a log to check whether permissions were changed prior to the segmentation fault?

The segmentation fault is occurring when taking the scoped lock prior to a write:

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 is an instance of SharedDataCommon (see below) encapsulating the boost::interprocess components.

I set temporarily set umask so the shared memory is readable by multiple Linux users.

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

I don't see anything which explains why the problem would occur some of the time?

Why are you using all these separate named entities, when you could simply use unnamed interprocess synchronization primitives inside the shared memory segment? See eg Boost Interprocess share memory deletion, permissions and output files (second example).

That at once removes a race condition between retrieving all the shared objects and actually synchronizing on the primitives.


The only thing I can reasonably see being outside the shared object is the named_mutex so you could synchronize the actual creation of the shared memory segment. However, looking at your code it looks like you fail to do precisely that:

    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));

The mutex is created after the segment. Now, this may not be a problem when you control the order in which server and clients start. However, in such a case there clearly is no need for the separate named-mutex to exist.


It's also worrying that you destroy the memory without any synchronization:

destroyMemory(tag);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM