Повысить межпроцессный процесс named_mutex, вызывающий ошибку сегментации - PullRequest
0 голосов
/ 30 мая 2018

Я использую boost interprocess для совместного использования памяти, но очень редко получаю ошибку сегментации, когда пытаюсь использовать boost :: interprocess: named_mutex с использованием boost :: interprocess :: scoped_lock.

Я только запускаю процесс записи.Этот процесс владеет общей памятью и не уничтожает ее (если приложение не закрывается).Приложение создает разделяемую память, используя класс SharedDataCommon (см. Нижнюю часть вопроса), который включает в себя все внутренние операции наддува, а затем я вызываю метод write (), который пытается получить named_mutex, но вызывает ошибки.

ошибка сегментации возникает в

boost / interprocess / sync / 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 является экземпляромSharedDataCommon (см. ниже), инкапсулирующих компоненты boost :: interprocess.

Я установил временно установленный 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 голосов
/ 30 мая 2018

Почему вы используете все эти отдельные именованные объекты, когда вы можете просто использовать безымянные примитивы синхронизации между процессами внутри сегмента общей памяти?См., Например, Ускорение удаления общей памяти между процессами, разрешения и выходные файлы (второй пример).

Это сразу устраняет условие гонки между извлечением всех общих объектов и фактической синхронизацией на примитивах.


Единственное, что я могу разумно увидеть за пределами общего объекта, это 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);
...