Пример использования бустер-обновляемых мьютексов - PullRequest
7 голосов
/ 09 октября 2010

У меня есть многопоточное серверное приложение, которое нуждается в мьютекс-блокировках для некоторой общей памяти.

Общая память - это в основном карты sTL и т. Д.

Большую часть времени я просто читаю изкарта.Но мне также необходимо время от времени добавлять к нему.

например, typedef std :: map MessageMap;Карта сообщений msgmap;boost: shared_mutex access _;

void ProcessMessage(Message* message)
{
  //  Access message... read some stuff from it  message->...

  UUID id = message->GetSessionID();

  // Need to obtain a lock here. (shared lock? multiple readers)
  // How is that done?
  boost::interprocess::scoped_lock(access_);

  // Do some readonly stuff with msgmap
  MessageMap::iterator it = msgmap.find();
  // 

  // Do some stuff...

  // Ok, after all that I decide that I need to add an entry to the map.
  // how do I upgrade the shared lock that I currently have?
  boost::interprocess::upgradable_lock


  // And then later forcibly release the upgrade lock or upgrade and shared lock if I'm not looking
  // at the map anymore.
  // I like the idea of using scoped lock in case an exception is thrown, I am sure that
  // all locks are released.
}

РЕДАКТИРОВАТЬ: Я мог бы путать различные типы блокировки.

В чем разница между shared / upgrade и exclusive.то есть я не понимаю объяснения.Похоже, если вы просто хотите разрешить многим читателям, вам нужен общий доступ.А для записи в вашу общую память вам просто необходим доступ для обновления.Или вам нужен эксклюзив?Объяснение в boost не совсем понятно.

Доступ к обновлению получен, потому что вы можете написать.Но общий доступ означает, что вы определенно не будете писать, что это значит?

РЕДАКТИРОВАТЬ: Позвольте мне объяснить, что я хочу сделать, с большей ясностью.Я еще не доволен ответами.

Вот пример снова и снова, но с примером некоторого кода, который я также использую.Просто иллюстрация, а не фактический код.

typedef boost::shared_mutex Mutex;
typedef boost::shared_lock<Mutex> ReadLock;
typedef boost::unique_lock<Mutex> WriteLock;
Mutex mutex;
typedef map<int, int> MapType;    // Your map type may vary, just change the typedef
MapType mymap;

void threadoolthread() // There could be 10 of these.
{   
    // Add elements to map here
    int k = 4;   // assume we're searching for keys equal to 4
    int v = 0;   // assume we want the value 0 associated with the key of 4

    ReadLock read(mutex); // Is this correct?
    MapType::iterator lb = mymap.lower_bound(k);
    if(lb != mymap.end() && !(mymap.key_comp()(k, lb->first)))
    {
        // key already exists
    }
    else
    {
        // Acquire an upgrade lock yes?  How do I upgrade the shared lock that I already        have?
        // I think then sounds like I need to upgrade the upgrade lock to exclusive is that correct as well?

        // Assuming I've got the exclusive lock, no other thread in the thread pool will be able to insert.
        // the key does not exist in the map
        // add it to the map
        {
          WriteLock write(mutex, boost::adopt_lock_t());  // Is this also correct?
          mymap.insert(lb, MapType::value_type(k, v));    // Use lb as a hint to insert,
                                                        // so it can avoid another lookup
        }
        // I'm now free to do other things here yes?  what kind of lock do I have here, if any?  does the readlock still exist?
    }

Ответы [ 2 ]

11 голосов
/ 09 октября 2010

Вы сказали, что ваше приложение является многопоточным, поэтому вы должны использовать boost :: thread, а не boost :: interprocess.

Из документации (не проверенной) вы должны сделать это так:

typedef boost::thread::shared_mutex shared_mutex;
boost::thread::upgrade_lock<shared_mutex> readLock(access_);

// Read access...

boost::thread::upgrade_to_unique_lock<shared_mutex> writeLock(readLock);

// Write access..

Также обратите внимание, что вы получаете it при блокировке доступа для чтения, поэтому кто-то может удалить этот узел, и он больше не действителен, когда вы попадете в раздел записи. НЕПРАВИЛЬНО, извините.

РЕДАКТИРОВАТЬ: Я думаю, что объяснение в повышение ясно ясно.Давайте все равно попробуем перефразировать его:

Существует три основных типа концепций мьютекса (я не считаю TimedLockable, поскольку он не связан с вашим вопросом):

  • Lockable - просто простой, эксклюзивный мьютекс владения.Если кто-то блокирует () это, никто не может заблокировать () это снова, пока владелец не разблокирует () это.boost :: thread :: mutex реализует эту концепцию.Чтобы заблокировать эту концепцию в стиле RAII, используйте lock_guard или unique_lock для более сложного интерфейса.
  • SharedLockable - это Lockable с дополнительным «общим» владением.Вы можете получить эксклюзивное право собственности с помощью lock () или общее право собственности с помощью lock_shared ().Если вы заблокируете общую часть, вы не сможете обновить свою собственность до эксклюзивной.Вам необходимо снова разблокировать unlock_shared () и lock (), что означает, что кто-то другой может изменить защищенный ресурс между unlock_shared () и lock ().Это полезно, когда вы априори знаете, какой тип доступа к ресурсу вы будете делать.shared_mutex реализует эту концепцию.Используйте lock_guard или unique_lock, чтобы получить исключительное право собственности, и shared_lock, чтобы получить общее владение.
  • UpgradeLockable - это SharedLockable, который позволяет вам перейти от общего владения к исключительному владению без разблокировки.shared_mutex также реализует эту концепцию.Вы можете использовать вышеупомянутые блокировки, чтобы получить исключительную или общую собственность.Чтобы получить обновляемое совместное владение, используйте upgrade_lock и обновите его с помощью upgrade_to_unique_lock.
5 голосов
/ 09 октября 2010

Вы не хотите boost-interprocess, если вы используете только один процесс. Как следует из названия библиотеки, она используется для межпроцессного взаимодействия (IPC). Скорее всего, вы хотите использовать boost-thread концепции мьютекса и блокировки .

#include <boost/thread/locks.hpp>  
#include <boost/thread/shared_mutex.hpp>  

int
main()
{
    typedef boost::shared_mutex Mutex;
    typedef boost::shared_lock<Mutex> ReadLock;
    typedef boost::unique_lock<Mutex> WriteLock;
    Mutex mutex;

    {
        // acquire read lock
        ReadLock read( mutex );

        // do something to read resource
    }

    {
        // acquire write lock
        WriteLock write( mutex, boost::adopt_lock_t() );

        // do something to write resource
    }
}

В списке рассылки Boost есть запись , объясняющая это.

...