Мустексный массив Boost Threads - PullRequest
5 голосов
/ 30 июня 2010

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

Вопрос в том, возможно ли (и если да, то как?) реализовать эффективный массив блокировок, чтобы одновременно могли блокироваться только части матрицы.

Рассматриваемая матрица может быть довольно большой, порядка 50 ^ 2 блоков.мое первоначальное предположение состоит в том, чтобы использовать динамически распределенный вектор / карту мьютексов.

Это хороший подход?Лучше вместо этого использовать несколько условных переменных?Есть ли лучший подход?

Ответы [ 2 ]

6 голосов
/ 30 июня 2010

Используйте один замок. Но вместо того, чтобы использовать его для защиты всей матрицы, используйте его для защиты std::set (или boost::unordered_set), который сообщает, какие блоки «заблокированы».

Как то так.

class Block;

class Lock_block
{
public:
   Lock_block( Block& block ) : m_block(&block)
   {
      boost::unique_lock<boost::mutex> lock(s_mutex);
      while( s_locked.find(m_block) != s_locked.end() )
      {
         s_cond.wait(lock);
      }
      bool success = s_locked.insert(m_block).second;
      assert(success);
   }

   ~Lock_block()
   {
      boost::lock_guard<boost::mutex> lock(s_mutex);
      std::size_t removed = s_locked.erase(m_block);
      assert(removed == 1);
      s_cond.notify_all();
   }
private:
   Block* m_block;

   static boost::mutex s_mutex;
   static boost::condition s_cond;
   static std::set<Block*> s_locked;
};
1 голос
/ 30 июня 2010

Это может быть несколько подходов, которые вы можете использовать:

  1. Предварительно выделить массив, если CriticalSection / Mutexes (2500 не так много), и использовать индекс блока в качестве индекса блокировки длясобрать блок доступа;перед обновлением блокируйте все блоки, которые вы хотите изменить;сделать обновление;unlock;

  2. Если время вычислений значительно больше, чем Lock / Unlock, скопируйте содержимое блока в контексте потока и оставьте блок разблокированным в течение этого времени;перед обновлением block заблокируйте его снова и убедитесь, что он не был обновлен другим потоком (если это актуально для этого);если он был обновлен другим потоком, повторите операцию;

  3. Если размер содержимого блока невелик, используйте атомарный обмен данными для обновления содержимого блока, блокировки не требуются;просто не уверен, используете ли вы данные из одного блока для вычисления данных для другого, в этом случае требуется блокировка для всех обновленных блоков;

  4. Есть ли операция чтения в матрице?Если да, используйте блокировки чтения / записи для повышения производительности.

...