Пример использования буст-обновляемых мьютексов
У меня есть многопоточное серверное приложение, которое нуждается в мьютекс-блокировке некоторой общей памяти.
Общая память - это в основном карты 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.
}
РЕДАКТИРОВАТЬ: Я мог бы путать различные типы блокировки.
Какая разница между расшаренным / апгрейдом и эксклюзивным. т.е. я не понимаю объяснения. Похоже, если вы просто хотите разрешить многим читателям, вам нужен общий доступ. А для записи в вашу общую память вам просто необходим доступ для обновления. Или вам нужен эксклюзив? Объяснение в 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 ответа
Вы сказали, что ваше приложение является многопоточным, поэтому вы должны использовать 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.
Ты не хочешь 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 также есть сообщение, объясняющее это.