Увеличить сбой межпроцессного мьютекса вместо ожидания блокировки?

Я занимаюсь этим уже несколько дней (даже опубликовано на форуме Boost), и возможность заставить второй процесс распознавать заблокированный мьютекс просто не работает. Пожалуйста помоги. Это код:

Общий заголовочный файл: SharedObject.hpp

#ifndef SHAREDOBJECT_HPP 
#define SHAREDOBJECT_HPP 
#include <iostream>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/list.hpp>
#include <time.h>//for sleep 
//--------for mutexes 
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <boost/interprocess/sync/upgradable_lock.hpp>

#define MUTEX_SHARED_MEMORY_NAME "NavSharedMemoryMutex" 
#define DATAOUTPUT "OutputFromObject" 
#define INITIAL_MEM 650000 
using namespace std; 
namespace bip = boost::interprocess; 

class SharedMutex 
{ 
private: 
    typedef bip::interprocess_upgradable_mutex upgradable_mutex_type; 
    mutable upgradable_mutex_type mutex; 
    volatile int counter;     
public: 
    void lockWithReadLock() const { bip::sharable_lock<upgradable_mutex_type> lock(mutex); } 
    void lockWithWriteLock() { bip::scoped_lock<upgradable_mutex_type> lock(mutex); } 
}; 

//-------------------------------------- SharedMemoryObject 
class SharedObject 
{ 
public: 
    SharedMutex* sharedMutex;   
}; 

typedef bip::allocator<SharedObject, bip::managed_shared_memory::segment_manager> ShmemAllocator; 
typedef bip::list<SharedObject, ShmemAllocator> SharedMemData; 

#endif /* SHAREDOBJECT_HPP */ 

Это первая программа:

#include "SharedObject.hpp" 

int main() 
{ 
    //-----------Create shared memory and put shared object into it 
    bip::managed_shared_memory* seg; 
    SharedMemData *sharedMemOutputList; 
    bip::shared_memory_object::remove(DATAOUTPUT); 
    seg = new bip::managed_shared_memory(bip::create_only, DATAOUTPUT, INITIAL_MEM); 
    const ShmemAllocator alloc_inst(seg->get_segment_manager()); 
    sharedMemOutputList = seg->construct<SharedMemData>("TrackOutput")(alloc_inst); 

    std::size_t beforeAllocation = seg->get_free_memory(); 
    std::cout<<"\nBefore allocation = "<< beforeAllocation <<"\n"; 
    SharedObject temp; 
    sharedMemOutputList->push_back(temp); 


    //-------------------Create a shared memory for holding a mutex 
    bip::shared_memory_object::remove(MUTEX_SHARED_MEMORY_NAME);//BUG: If another program also removes this, then there won't be any shared memory remaining. This problem has to be handled better. This is not the right way to deal with shared mutexes. 
    bip::shared_memory_object shm(bip::create_only, MUTEX_SHARED_MEMORY_NAME, bip::read_write); 
    shm.truncate(sizeof (SharedMutex)); //Allocate memory in shared memory for the mutex 
    bip::mapped_region region(shm, bip::read_write); // Map the whole shared memory into this process.         
    new (region.get_address()) SharedMutex; // Construct the SharedMutex using placement new 
    temp.sharedMutex = static_cast<SharedMutex *> (region.get_address()); //Store the mutex object address for future reference 

    { 
        std::cout<<"Program 1: Before first locking -------------------------- 1 v\n"; 
        temp.sharedMutex->lockWithWriteLock(); 
        const unsigned int SLEEP_TIME_IN_SECOND = 60; 
        std::cout<<"Program 1: sleep for "<< SLEEP_TIME_IN_SECOND << "\n"; 
        sleep(SLEEP_TIME_IN_SECOND); 
        std::cout<<"Program 1: Finished sleeping\n"; 
    } 
    std::cout<<"Program 1: unlocked -------------------------------------- 1 ^\n"; 


    seg->destroy<SharedMemData>("TrackOutput"); 
    delete seg;       
    return 0; 
}//main

А это вторая программа:

#include "SharedObject.hpp" 
#define CREATE_SEPARATE_MUTEX 

int main() 
{ 
    bip::managed_shared_memory segment(bip::open_only, DATAOUTPUT); //Open the managed segment 

    SharedMemData* sharedMemoryTrackOutputList = segment.find<SharedMemData>("TrackOutput").first; //Find the list using the c-string name 
    assert(sharedMemoryTrackOutputList);     
    std::cout << "SharedMemoryData address found at = " << (void *) sharedMemoryTrackOutputList << "\n"; 
    std::cout << "size = " << sharedMemoryTrackOutputList->size() << "\n"; 
    SharedMemData::iterator iter = sharedMemoryTrackOutputList->begin(); 

#ifndef CREATE_SEPARATE_MUTEX 
    //-------------------Create a shared memory for holding a mutex 
    bip::shared_memory_object shm(bip::open_or_create, MUTEX_SHARED_MEMORY_NAME, bip::read_write); 
    shm.truncate(sizeof (SharedMutex)); //Allocate memory in shared memory for the mutex 
    bip::mapped_region region(shm, bip::read_write); // Map the whole shared memory into this process.         
    new (region.get_address()) SharedMutex; // Construct the SharedMutex using placement new 
    (*iter).sharedMutex = static_cast<SharedMutex *> (region.get_address()); //Store the mutex object address for future reference 
#endif 

    { 
        std::cout<<"Program 2: Before first locking -------------------------- 1 v\n"; 
        (*iter).sharedMutex->lockWithWriteLock(); 
        const unsigned int SLEEP_TIME_IN_SECOND = 1; 
        std::cout<<"Program 2: sleep for "<< SLEEP_TIME_IN_SECOND << "\n"; 
        sleep(SLEEP_TIME_IN_SECOND); 
        std::cout<<"Program 2: Finished sleeping\n"; 
    } 
    std::cout<<"Program 2: unlocked -------------------------------------- 1 ^\n";     

    return 0; 
}//main 

Программа 1 работает нормально.
Программа 2 дает следующий результат:

SharedMemoryData address found at = 0x7f0a4c2b8118 
size = 1 
Program 2: Before first locking -------------------------- 1 v 
terminate called after throwing an instance of 'boost::interprocess::lock_exception' 
  what():  boost::interprocess::lock_exception 
Aborted (core dumped)

Сначала я запускаю программу 1, которая блокирует мьютекс и держит его заблокированным в течение 60 секунд. В это время я запускаю программу 2, чтобы посмотреть, ждет ли она блокировки, но она падает. Как я могу заставить программу 2 ждать мьютекса, пока программа 1 не закончит запись в разделяемую память?


person Nav    schedule 18.10.2015    source источник
comment
эм, этот пост еще НЕ принят в список рассылки. - так что похоже, что вы на самом деле ничего не публиковали в списке рассылки Boost. Вы должны быть участником в первую очередь.   -  person sehe    schedule 18.10.2015


Ответы (2)


Хорошо, вот некоторые проблемы с вашим кодом.

  1. SharedMutex хранится в другой области памяти, которая не отображается во второй программе.

  2. Сопоставляемая область может иметь другой базовый адрес, поэтому необработанные указатели не будут работать в этой среде. Вместо этого используйте boost::interprocess::offset_ptr. Обратите внимание, однако, что они работают для указателей на один и тот же сегмент памяти, поэтому имеет смысл поместить ваши SharedMutex и SharedObject в один и тот же сегмент (или вместо всего этого использовать named_mutex).

  3. В main1 вы копируете temp в общую память перед изменением переменной-члена sharedMutex. Вы должны убедиться, что в разделяемой памяти ваш указатель (offset_ptr-to-be) действительно действителен.

  4. Когда вы пытаетесь заблокировать с помощью scoped_lock, используя вашу функцию lockWithWriteLock, блокировка снимается сразу после выхода из функции. Поэтому, как только вы исправите все вышеперечисленное и избавитесь от краха, вы все равно не получите ожидаемого результата — логика вашего кода должна быть изменена.

и код:

sharedObject.hpp

#ifndef SHAREDOBJECT_HPP 
#define SHAREDOBJECT_HPP 
#include <iostream>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/list.hpp>
#include <time.h>//for sleep 
//--------for mutexes 
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <boost/interprocess/sync/upgradable_lock.hpp>

#define MUTEX_SHARED_MEMORY_NAME "NavSharedMemoryMutex" 
#define DATAOUTPUT "OutputFromObject" 
#define INITIAL_MEM 650000 
using namespace std;
namespace bip = boost::interprocess;

class SharedMutex
{
public:
    typedef bip::interprocess_upgradable_mutex upgradable_mutex_type;
    mutable upgradable_mutex_type mutex;
};

//-------------------------------------- SharedMemoryObject 
class SharedObject
{
public:
    SharedMutex* sharedMutex;
};

typedef bip::allocator<SharedObject, bip::managed_shared_memory::segment_manager> ShmemAllocator;
typedef bip::list<SharedObject, ShmemAllocator> SharedMemData;

#endif /* SHAREDOBJECT_HPP */

Программа1:

#include "SharedObject.hpp"

int main()
{
    //-----------Create shared memory and put shared object into it 
    bip::managed_shared_memory* seg;
    SharedMemData *sharedMemOutputList;
    bip::shared_memory_object::remove(DATAOUTPUT);
    seg = new bip::managed_shared_memory(bip::create_only, DATAOUTPUT, INITIAL_MEM);
    const ShmemAllocator alloc_inst(seg->get_segment_manager());
    sharedMemOutputList = seg->construct<SharedMemData>("TrackOutput")(alloc_inst);

    SharedObject temp;

    //-------------------Create a shared memory for holding a mutex 
    bip::shared_memory_object::remove(MUTEX_SHARED_MEMORY_NAME);//BUG: If another program also removes this, then there won't be any shared memory remaining. This problem has to be handled better. This is not the right way to deal with shared mutexes. 
    bip::shared_memory_object shm(bip::open_or_create, MUTEX_SHARED_MEMORY_NAME, bip::read_write);
    shm.truncate(sizeof(SharedMutex)); //Allocate memory in shared memory for the mutex 
    bip::mapped_region region(shm, bip::read_write); // Map the whole shared memory into this process.         
    new (region.get_address()) SharedMutex; // Construct the SharedMutex using placement new 
    temp.sharedMutex = static_cast<SharedMutex *> (region.get_address()); //Store the mutex object address for future reference 

    std::cout << "Region address " << region.get_address() << "\n";

    sharedMemOutputList->push_back(temp);

    //initiate scope for scoped mutex
    {
        std::cout << "Program 1: Going to do 1st locking -------------------------- 1 v\n";
        bip::scoped_lock<bip::interprocess_upgradable_mutex> lock(temp.sharedMutex->mutex);
        const unsigned int SLEEP_TIME_IN_SECOND = 10;
        std::cout<<"Program 1: locked. Now sleep for "<< SLEEP_TIME_IN_SECOND << "\n";
        sleep(SLEEP_TIME_IN_SECOND);
        std::cout << "Program 1: Finished sleeping\n";
    }
    std::cout << "Program 1: unlocked ----------------------------------------- 1 ^\n";

    //seg->destroy<SharedMemData>("TrackOutput");delete seg;
    return 0;
}//main

и Программа 2:

#include "SharedObject.hpp"
#define READ_LOCK_TESTING
#ifndef READ_LOCK_TESTING
    #define WRITE_LOCK_TESTING
#endif
int main()
{
    bip::managed_shared_memory segment(bip::open_only, DATAOUTPUT); //Open the managed segment 

    SharedMemData* sharedMemoryTrackOutputList = segment.find<SharedMemData>("TrackOutput").first; //Find the list using the c-string name 
    assert(sharedMemoryTrackOutputList);
    std::cout << "SharedMemoryData address found at = " << (void *)sharedMemoryTrackOutputList << "\n";
    std::cout << "size = " << sharedMemoryTrackOutputList->size() << "\n";
    SharedMemData::iterator iter = sharedMemoryTrackOutputList->begin();

    bip::shared_memory_object shm(bip::open_or_create, MUTEX_SHARED_MEMORY_NAME, bip::read_write);
    bip::mapped_region region(shm, bip::read_write); // Map the whole shared memory into this process.       

    std::cout << "Region address " << region.get_address() << "\n";

    //Initiate the scope for the scoped mutex
    {
        std::cout << "Program 2: Going to do 2nd locking -------------------------- 2 v\n";
        iter->sharedMutex = static_cast<SharedMutex*>(region.get_address());
#ifdef WRITE_LOCK_TESTING        
        bip::scoped_lock<bip::interprocess_upgradable_mutex> lock((*iter).sharedMutex->mutex);//write lock
#endif        
#ifdef READ_LOCK_TESTING
        bip::sharable_lock<bip::interprocess_upgradable_mutex> lock((*iter).sharedMutex->mutex);//read lock
#endif        
        const unsigned int SLEEP_TIME_IN_SECOND = 10;
        std::cout << "Program 2: locked. Now sleep for " << SLEEP_TIME_IN_SECOND << "\n";
        sleep(SLEEP_TIME_IN_SECOND);
        std::cout << "Program 2: Finished sleeping\n";
    }
    std::cout << "Program 2: unlocked ------------------------------------------ 2 ^\n";

    return 0;
}//main
person Rostislav    schedule 18.10.2015
comment
Большое спасибо Ростислав. Я пробовал named_mutex и раньше, но это не сработало. Возможно, я реализовал это неправильно. Здесь могли бы помочь реальные примеры кода, потому что я пробовал много вещей и ссылался на пример кода повышения, но блокировка просто не работает. Это было в крайнем случае, что я написал здесь. Не могли бы вы обновить свой ответ рабочим кодом? Я уверен, что это поможет и многим другим программистам. - person Nav; 18.10.2015
comment
@Nav Вот рабочий код. Сравните его со своим и посмотрите на различия. offset_ptr там не используется, но я думаю, вы поняли идею. main1 main2 main.h - person Rostislav; 18.10.2015
comment
Спасибо @Rostislav. Очень признателен. Я добавил код в ваш ответ. Мне также придется добавить некоторую обработку исключений, поскольку, если программы запускаются немного не по порядку, они имеют тенденцию к сбою, потому что не могут найти разделяемую память или межпроцессное исключение, говорящее, что он не может найти файл или каталог. . Я справлюсь с этим. Ваша помощь в прояснении сомнений по поводу того, как решить блокировку, очень помогла. - person Nav; 19.10.2015

Ростислав предложил использовать именованные мьютексы, поэтому просто привел пример именованных мьютексов (хотя я хотел блокировки чтения-записи, и эти блокировки, похоже, не поддерживают именованные мьютексы... Хотя я могу ошибаться).

Программа 1:

#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <fstream>
#include <iostream>
#include <cstdio>


int main ()
{
   using namespace boost::interprocess;
   try
   {
      struct mutex_remove
      {
         mutex_remove() { named_mutex::remove("fstream_named_mutex"); }
         ~mutex_remove(){ named_mutex::remove("fstream_named_mutex"); }
      } remover;

      //Open or create the named mutex
      named_mutex mutex(open_or_create, "fstream_named_mutex");

      {
          std::cout<<"gonna lock\n";
          scoped_lock<named_mutex> lock(mutex);
          const unsigned int SLEEP_TIME_IN_SECOND = 10;
          std::cout<<"Program 1: locked. Now sleep for "<< SLEEP_TIME_IN_SECOND << "\n";
          sleep(SLEEP_TIME_IN_SECOND);
      }
      std::cout<<"unlocked\n";
   }
   catch(interprocess_exception &ex){
      std::cout << ex.what() << std::endl;
      return 1;
   }
   return 0;
}

Программа 2:

#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <fstream>
#include <iostream>
#include <cstdio>


int main ()
{
   using namespace boost::interprocess;
   try{
      //Open or create the named mutex
      named_mutex mutex(open_or_create, "fstream_named_mutex");

      {
          std::cout<<"gonna lock\n";
          scoped_lock<named_mutex> lock(mutex);
          const unsigned int SLEEP_TIME_IN_SECOND = 5;
          std::cout<<"Program 2: locked. Now sleep for "<< SLEEP_TIME_IN_SECOND << "\n";
          sleep(SLEEP_TIME_IN_SECOND);
      }
   }
   catch(interprocess_exception &ex){
      std::cout << ex.what() << std::endl;
      return 1;
   }
   return 0;
}
person Nav    schedule 20.10.2015