C ++ Pthread - Как сделать доступ к карте потокобезопасным? - PullRequest
3 голосов
/ 11 декабря 2011

У меня есть карта как переменная-член и несколько потоков, которые обращаются к карте (доступ для чтения и записи).Теперь я должен убедиться, что только ОДИН поток имеет доступ к карте.Но как мне это расставить?Что является лучшим решением для этого?

Ответы [ 4 ]

4 голосов
/ 11 декабря 2011

Boost содержит несколько хороших реализаций блокировки для общего доступа. Посмотрите документацию .

В вашем случае вам, вероятно, понадобится блокировка чтения-записи, поскольку блокировка взаимного исключения, вероятно, излишня, если у вас много операций чтения и очень мало операций записи.

3 голосов
/ 11 декабря 2011

Вам необходимо синхронизировать доступ к вашей карте, например, с помощью POSIX mutex . Ссылка содержит несколько простых примеров использования переменных взаимного исключения.

1 голос
/ 11 декабря 2011

Если у вас есть недавний компилятор, вы можете использовать std::mutex (который основан на улучшенной реализации).Это часть C ++ 11, поэтому она не везде реализована.GCC-4.6 работает довольно хорошо, хотя.Базовая реализация - это потоки POSIX в linux и потоки Windows в Windows.

1 голос
/ 11 декабря 2011

На самом деле предпосылка о том, что только один поток должен иметь доступ к 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;
};

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

Кроме того, я рекомендую вам держать карту под жестким контролем, помещая ее в мельчайший объект, который имеет смысл, и предоставляя только те операции, которые вам нужны.Наименьшее количество методов имеет доступ к карте, тем меньше вероятность пропустить одну точку доступа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...