boost::interprocess общая память между 32- и 64-битными процессами

Я пытаюсь заставить boost::interprocess разделить память между 32-битными и 64-битными процессами. Эта запись в системе отслеживания ошибок предполагает, что это возможно в Boost 1.49, и именно это Я использую.

В качестве теста я попытался поделиться неподписанным целым числом. Это простое приложение Qt с двумя кнопками.

#define SHARED_MEMORY_NAME "My shared memory"
#define SHARED_VAR_NAME "testVar"
namespace bip = boost::interprocess;

void on_createMemButton_clicked()
{
  std::cout << "sizeof(unsigned int): " << sizeof(unsigned int) << std::endl;
  bip::shared_memory_object::remove(SHARED_MEMORY_NAME);
  bip::managed_shared_memory mem(bip::create_only, SHARED_MEMORY_NAME, 12345);
  mem.construct<unsigned int>(SHARED_VAR_NAME)(42);
  std::cout << "Created shared memory " << SHARED_MEMORY_NAME << std::endl;
}

void on_accessMemButton_clicked()
{
  try
  {
    std::cout << "sizeof(unsigned int): " << sizeof(unsigned int) << std::endl;
    bip::managed_shared_memory mem(bip::open_only, SHARED_MEMORY_NAME);
    std::pair<unsigned int*, size_t> p = mem.find<unsigned int>(SHARED_VAR_NAME);
    std::cout<< "got " << p.second << " numbers " << std::endl;
    if (p.second > 0)
      std::cout << "first number is: " << *p.first << std::endl;

    bip::shared_memory_object::remove(SHARED_MEMORY_NAME);
  }
  catch (bip::interprocess_exception e)
  {
    std::cout << "Shared mem " << SHARED_MEMORY_NAME << " not found" << std::endl;
  }
}

Если я создаю или получаю доступ к общей памяти из процессов с одинаковой разрядностью, это работает без проблем. Но если я создам память в 64-битном процессе и прочитаю из 32-битного процесса, процесс войдет в функцию managed_shared_memory::find() и больше никогда не вернется. Если я попробую наоборот, 64-битный процесс снова завершится ошибкой в ​​managed_shared_memory::find(), на этот раз с нарушением прав доступа. Использование managed_windows_shared_memory дало те же результаты.

Есть ли способ заставить это работать?


person Andreas Haferburg    schedule 30.08.2013    source источник
comment
Как странно... В ОС в стиле Unix я определенно ожидал, что это сработает, но я понятия не имею, как это работает под Windows.   -  person Mats Petersson    schedule 30.08.2013
comment
Вы должны использовать что-то вроде uint32_t вместо unsigned int в случае межархитектурного кода, это может быть проблемой в зависимости от вашего компилятора. Я также использую boost ipc для связи x86 64‹-›32 в Windows с использованием компилятора Visual C++ 10.0 с boost 1.50, и он работает как шарм.   -  person ch0kee    schedule 26.09.2013
comment
У меня та же проблема. Есть результаты?   -  person Viatorus    schedule 29.07.2015
comment
@Viatorus В итоге мы использовали Windows API напрямую (CreateFileMapping, CreateMutex(NULL, FALSE, ...)).   -  person Andreas Haferburg    schedule 10.08.2015


Ответы (2)


У меня такая же проблема. У меня была DLL, работающая внутри другого процесса, и приложение контроллера, скомпилированное отдельно. Мои функции find() и find_or_construct() зависали, что выглядело как мертвая блокировка. Изменение на null_mutex_family ничего не дало.

Проблема оказалась в типе char, используемом для компиляции DLL и приложения контроллера. Настройка обоих для использования многобайтовых символов исправила это для меня (используя MSVC).

Я добавил эту строку в свой код, чтобы она больше никогда меня не кусала, прямо перед доступом к моему экземпляру manage_shared_memory.

if (sizeof(char) != 2) throw std::exception("Set your chars right");

Если вы попытаетесь найти объект, созданный с использованием одного типа char, из приложения, использующего другой тип, boost будет зависать в бесконечном цикле (что у меня не хватило терпения попытаться найти).

person MFT    schedule 19.12.2016
comment
sizeof(char) всегда равно 1, потому что sizeof измеряется в charс. Вы имели в виду sizeof(TCHAR)? Также проверьте static_assert для проверки во время компиляции вместо проверки во время выполнения. - person rustyx; 04.08.2020

У меня была такая же проблема в Windows при компиляции с набором инструментов vc142 в VS2019. Я использовал boost 1.73, но думаю, что boost 1.60+ тоже подойдет. Кроме того, я использовал управляемую память Windows, а не обычную управляемую память, которую использовал первоначальный вопросник. Но я думаю, что мое решение все еще применимо.

Я смог решить это после того, как заметил, что при компиляции

    using ManagedShMem = bip::managed_windows_shared_memory;
    ManagedShMem segment(bip::open_or_create, pcShMemName, uiMemSize, 0, perms); // will have issues, if used for crossplatform interaction.

На моей 32-битной платформе фактически вызывался этот конструктор:

    boost::interprocess::basic_managed_windows_shared_memory<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index>::basic_managed_windows_shared_memory<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index>(boost::interprocess::open_or_create_t __formal, const char * name, unsigned int size, const void * addr, const boost::interprocess::permissions & perm);

В то время как на 64-битной платформе:

    boost::interprocess::basic_managed_windows_shared_memory<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>::basic_managed_windows_shared_memory<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>(boost::interprocess::open_or_create_t __formal, const char * name, unsigned __int64 size, const void * addr, const boost::interprocess::permissions & perm);

Как видите, параметры шаблона offset_ptr различаются между двумя. Это приводит к несколько различным предположениям о двоичной структуре между 32-разрядными и 64-разрядными процессами, что также приводит к проблемам с использованием общей памяти.

Все, что вам нужно сделать, это сделать тип вашего управляемого сегмента полностью идентичным на всех платформах. Итак, мое решение было простым — просто перечислите параметры шаблона явно и совместимо с 64-битной платформой:

    using ManagedShMem = bip::basic_managed_windows_shared_memory
    <char,
    boost::interprocess::rbtree_best_fit<
        boost::interprocess::mutex_family,
        boost::interprocess::offset_ptr<
            void,
            __int64,
            unsigned __int64,
            0>,
        0>,
    boost::interprocess::iset_index>;
    ManagedShMem segment(bip::open_or_create, pcShMemName, uiMemSize, 0, perms); // now works well on both platforms!

После этого я смог общаться с моим 32-битным процессом с моим 64-битным процессом через разделяемый сегмент памяти (и наоборот).

P.S. Кроме того, имейте в виду, что 32-разрядная платформа ограничивает доступ к памяти. Как правило, вы не можете получить более 2 ГБ (хотя у меня не было проблем с 1,5 ГБ, но это зависит от многих других вещей) общей памяти для 32-разрядного процесса Windows. Это означает, что если вы решили выделить 2 ГБ или более в 64-битном процессе (что легко выполнимо), ваш конструктор сегментов в 32-битном процессе получит исключение, потому что boost (через Win32 API) откажется отображать такой большой кусок памяти.

person Ilya Lipovsky    schedule 03.08.2020