На самом деле предпосылка о том, что только один поток должен иметь доступ к map
в данный момент времени, слегка отключена.
Одновременные чтения в порядке, чего вы хотите избежать, так это наличия потока, модифицирующего картув то время как другие читают его.
В зависимости от необходимого вам уровня детализации, вы можете рассмотреть возможность блокировки чтения / записи, которая позволит нескольким чтениям проходить параллельно.
Точное использование было продемонстрировано здесь с использованием Boost:
boost::shared_mutex _access;
void reader()
{
// get shared access
boost::shared_lock<boost::shared_mutex> lock(_access);
// now we have shared access
}
void writer()
{
// get upgradable access
boost::upgrade_lock<boost::shared_mutex> lock(_access);
// get exclusive access
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
// now we have exclusive access
}
После этого нужно просто обернуть доступ к карте.Например, вы можете использовать общую структуру прокси:
template <typename Item, typename Mutex>
class ReaderProxy {
public:
ReaderProxy(Item& i, Mutex& m): lock(m), item(i) {}
Item* operator->() { return &item; }
private:
boost::shared_lock<Mutex> lock;
Item& item;
};
template <typename Item, typename Mutex>
class WriterProxy {
public:
WriterProxy(Item& i, Mutex& m): uplock(m), lock(uplock), item(i) {}
Item* operator->() { return &item; }
private:
boost::upgrade_lock<Mutex> uplock;
boost::upgrade_to_unique_lock<Mutex> lock;
Item& item;
};
И вы можете использовать их как:
class Foo {
typedef ReaderProxy< std::map<int, int>, boost::shared_mutex> Reader;
typedef WriterProxy< std::map<int, int>, boost::shared_mutex> Writer;
public:
int get(int k) const {
Reader r(map, m);
auto it = r->find(k);
if (it == r->end()) { return -1; }
return it->second;
}
void set(int k, int v) {
Writer w(map, m);
w->insert(std::make_pair(k, v));
}
private:
boost::shared_mutex m;
std::map<int, int> map;
};
Остерегайтесь итераторов, хотя ими можно безопасно управлять только тогда, когда мьютексудерживается текущим потоком.
Кроме того, я рекомендую вам держать карту под жестким контролем, помещая ее в мельчайший объект, который имеет смысл, и предоставляя только те операции, которые вам нужны.Наименьшее количество методов имеет доступ к карте, тем меньше вероятность пропустить одну точку доступа.