Как использовать boost :: thread mutex для синхронизации доступа на запись? - PullRequest
4 голосов
/ 18 сентября 2010

У меня есть вопрос новичка о Boost::Thread и Mutex.

Я хотел бы запустить много параллельных экземпляров следующего Worker, и все они пишут в один и тот же std::vector:

struct Worker {
  std::vector<double>* vec;
  Worker(std::vector<double>* v) : vec(v) {}
  void operator() {
    // do some long computation and then add results to *vec, e.g.
    for(std::size_t i = 0; i < vec->size(); ++i) {
      (*vec)[i] += some_value;
    }
  }
};

Я понимаю, что Рабочий должен заблокировать vec перед тем, как записать в него, и разблокировать его, когда это будет сделано (потому что все Рабочие записывают в один и тот же вектор).Но как мне это выразить?

Ответы [ 2 ]

8 голосов
/ 18 сентября 2010

Вам нужен boost :: mutex для защиты вектора, и вы можете использовать boost :: mutex :: scoped_lock, который заблокирует мьютекс в его конструкторе и разблокирует его в деструкторе

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

Чтобы начать, вы можете сделать что-то вроде:

struct Worker {
  boost::mutex &vec_mutex;

  Worker(std::vector<double>* v,boost::mutex &v_mutex) : vec(v),vec_mutex(v_mutex) {}
  void operator() {        
    // do some long computation and then add results to *vec, e.g.

    boost::mutex::scoped_lock lock(vec_mutex);
    for(std::size_t i = 0; i < vec->size(); ++i) {
      (*vec)[i] += some_value;
    }
  }

};

Для более сложных вещей вы должны инкапсулировать вектор и мьютекс дальше, или рано или поздно вы забудете, что они должны быть подключены, и вы получите доступ к vec где-нибудь, не удерживая блокировку, что приводит к очень трудным для отладки проблемы. Для таких задач, как этот пример, я бы предпочел, чтобы работники использовали свои собственные индивидуальные векторы и объединяли результат в управляющий поток, когда рабочие закончили.

0 голосов
/ 18 сентября 2010

ОТ, но полезная информация, я надеюсь - поскольку вы много раз обновляете этот вектор (или просто для лучшей практики), рассмотрите итераторы для итерации по элементам вектора. Ускорение рабочего кода без необходимости использования vector<double>::operator[] сократит общее время ожидания рабочих потоков.

for(std::vector<double>::iterator iter = vec->begin(); iter != vec->end(); ++iter) {
  *iter += some_value;
}
...