boost named_condition не пробуждает ожидающий процесс

У меня есть 2 процесса (производитель и потребитель), разделяющих очередь int в общей памяти, у меня есть процесс производителя, помещающий 2 числа в очередь, а затем он переходит в состояние ожидания, теряя блокировку мьютекса. Затем у меня есть потребительский процесс, удаляющий числа и печатающий их. Затем он уведомляет об условии, которого ожидает производитель. Затем потребитель продолжает самостоятельно ждать второго условия. После этого случая производитель не просыпается. Я использую один и тот же мьютекс между процессами. Пожалуйста, найдите весь код ниже.

Включить файл shared_memory.h:

#ifndef SharedMemory_h
#define SharedMemory_h

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/deque.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/offset_ptr.hpp>
#include <boost/interprocess/sync/named_condition.hpp>

using namespace boost::interprocess;

typedef allocator<offset_ptr<int>, managed_shared_memory::segment_manager> ShmemAllocator;
typedef deque<offset_ptr<int>, ShmemAllocator> Deque;

#endif 

Процесс производителя:

#include "shared_memory.h"

struct shm_remove
{
    shm_remove() { shared_memory_object::remove("MySharedMemory"); }
    ~shm_remove() { shared_memory_object::remove("MySharedMemory"); }
} remover;

struct mutex_remove
{
    mutex_remove() { named_mutex::remove("MyMutex"); }
    ~mutex_remove() { named_mutex::remove("MyMutex"); }
} mutex_remover;

//Create shared memory, mutex and condtion
managed_shared_memory segment(create_only, "MySharedMemory", 10000000);
named_mutex mutex(create_only,"MyMutex");
named_condition full(open_or_create,"FullCondition");
named_condition empty(open_or_create,"EmptyCondition");

const ShmemAllocator alloc_inst (segment.get_segment_manager());


int main() 
{
    Deque* MyDeque;
    offset_ptr<int> a, b;
    try{
        MyDeque = segment.construct<Deque>("MyDeque")(alloc_inst);
        try{
           a = static_cast<int*> (segment.allocate(sizeof(int)));
           b = static_cast<int*> (segment.allocate(sizeof(int)));
        }catch(bad_alloc &ex){
             std::cout << "Could not allocate int" << std::endl;
        }
    }catch(bad_alloc &ex){
        std::cout << "Could not allocate queue" << std::endl;
    }
    scoped_lock<named_mutex> lock(mutex);
    while(1)
    {
        while (MyDeque->size() == 2)
        {
            full.wait(lock);
            std::cout << "unlocked producer" << std::endl;
        }

        if (MyDeque->size() == 0)
        {
            *a = 2;
            MyDeque->push_back(a);
        }

        if (MyDeque->size() == 1)
        {
            *b = 4;
            MyDeque->push_back(b);
            empty.notify_one();
        }
    }
}

Потребительский процесс:

#include "shared_memory.h"

managed_shared_memory segment(open_only, "MySharedMemory");
Deque* MyDeque = segment.find<Deque>("MyDeque").first;

named_mutex mutex(open_only, "MyMutex");
named_condition full(open_only, "FullCondition");
named_condition empty(open_only, "EmptyCondition");

int main()
{
    scoped_lock<named_mutex> lock(mutex);
    while(1)
    {

         //volatile int size = MyDeque->size();
         while (MyDeque->size() == 0)
         {
             empty.wait(lock);
         }

         if (MyDeque->size() == 2)
         {
             std::cout << "Consumer: " << *MyDeque->front() << std::endl;
             MyDeque->pop_front();
         }

         if (MyDeque->size() == 1)
         {
             std::cout << "Consumer: " << *MyDeque->front() << std::endl;
             MyDeque->pop_front();
             full.notify_one();
         }
    }
}

В то время как отладка, кажется, идет нормально для первой итерации, производитель помещает числа 2 и 4 в дек, а затем ждет полного условия. Затем потребитель получает блокировку, печатает эти числа, выполняет notify_one при полном условии, а затем переходит в ожидание. После этого продюсер не просыпается.


person rudasi    schedule 18.07.2013    source источник
comment
Я не знаком с boost interprocess, но есть ли причина думать, что mutex в общей памяти работает в обоих процессах?   -  person Yakk - Adam Nevraumont    schedule 18.07.2013
comment
Пожалуйста, укажите явно, что все объекты синхронизации принадлежат Boost.Interprocess (т.е. пространству имен boost::interprocess), так как в библиотеке Boost.Thread есть и аналогичные объекты с другим функционалом.   -  person Igor R.    schedule 18.07.2013
comment
Я хотел бы думать, что это функционально, поскольку, когда вы пытаетесь получить именованный мьютекс, возникает исключение, если оно недоступно. Кроме того, когда я отлаживаю код с помощью точек останова, бывают случаи, когда потребитель пытается получить мьютекс, но не может, поскольку он есть у производителя. Только когда производитель делает ожидание и теряет мьютекс, потребитель получает его.   -  person rudasi    schedule 18.07.2013
comment
У меня есть пространство имен, использующее boost::interprocess. Я должен был поместить это в код.   -  person rudasi    schedule 18.07.2013
comment
@rudasi Я думаю, вам придется показать нам код, в котором вы создаете мьютекс и условия.   -  person doctorlove    schedule 18.07.2013
comment
Вероятно, это не связано, но было бы неплохо заблокировать мьютекс перед созданием или открытием сегмента общей памяти, чтобы гарантировать, что у производителя есть возможность инициализировать все до того, как потребитель получит к нему доступ.   -  person Casey    schedule 19.07.2013
comment
Я попробовал аналогичный код, но без использования именованных мьютексов и именованных условий, вместо этого я использовал обычные мьютексы и условия потока повышения. Я создал поток производителя и потребителя, все вроде синхронизировалось правильно и работало хорошо. Кажется, либо я делаю что-то неправильно с настройкой общей памяти и мьютекса/условий, либо, возможно, есть проблема с именованным мьютексом/условиями в boost. Какие-либо предложения?   -  person rudasi    schedule 19.07.2013
comment
shm_remove и mutex_remove кажутся странными классами? Они удаляют целевые объекты при их создании и снова удаляют при их уничтожении. Это похоже на шаблон RAII en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization, но отличается. В любом случае они не используются в этом коде, поэтому я их проигнорирую. Однако еще один момент: именованные условные переменные также сохраняются за пределами жизни любого процесса и, вероятно, также нуждаются в механизме удаления.   -  person Dale Wilson    schedule 08.08.2013
comment
Почему create_only для именованного мьютекса? Это сработает, если мьютекс уже существует (помните, что он постоянный). Я бы ожидал, что open_or_create.   -  person Dale Wilson    schedule 08.08.2013
comment
Это не позволило бы мне отредактировать комментарий выше, когда я понял, что делают shm_remove и mutex_remove: Статические оболочки вокруг main().   -  person Dale Wilson    schedule 08.08.2013
comment
Что делают статические оболочки, насколько я понимаю, они вызываются каждый раз при запуске и выходе процесса. Они удаляют общую память и мьютекс, но я думал, что они могут удалить их только в том случае, если к ним не подключен никакой другой процесс?   -  person rudasi    schedule 08.08.2013


Ответы (1)


Мьютекс не должен блокироваться при уведомлении. В этом причина тупика.

person Lukas Pauk    schedule 19.12.2013