Кажется, у меня возникла проблема с синхронизацией сбора данных. В этом конкретном классе у меня есть переменная сбора данных, мьютекса и условия, которая выглядит примерно так:
map<std::string, double> collection;
boost::mutex collectionMutex;
boost::condition_variable collectionConditional;
По большей части это работает. Однако недавно я добавил функцию, в которой я назначаю новое значение каждому значению в коллекции. В коллекции около 100-200 значений, так что не очень много; все задания выполняются очень быстро. Я также позаботился о том, чтобы на этом этапе не происходило никаких вычислений, это просто серия заданий. Вокруг назначений у меня есть код, который выглядит следующим образом (на основе ответа здесь на stackoverflow):
boost::mutex::scoped_lock lock(collectionMutex);
while(!lock.owns_lock())
{
collectionConditional.wait(lock);
}
// Assignments here
collectionConditional.notify_one();
В другом месте кода у меня есть функция, которая «читает» информацию из коллекции и выглядит примерно так:
double result = 0;
boost::mutex::scoped_lock lock(collectionMutex);
while(!lock.owns_lock())
{
collectionConditional.wait(lock);
}
result = collection["Some String"];
collectionConditional.notify_one();
Происходит следующее: когда вызывается моя функция write, она на некоторое время блокируется. В конечном итоге он выходит из строя, поэтому это не полный тупик, но период ожидания может быть длительным (несколько секунд). Это должно быть порядка миллисекунд или меньше.
Странно то, что я успешно использовал вышеописанную функцию записи раньше, и несколько потоков записывали в эту коллекцию данных без проблем. Причина, по которой я внес это изменение, заключается в перемещении централизованных обновлений этой коллекции в одно место, а не в зависимости от состояния времени выполнения других потоков.
Благодаря комментариям на мой вопрос, я сделал несколько вещей:
Прекратил использование оператора [] в функции чтения и сделал функцию чтения постоянной.
Прекращено использование условия
Использовал shared_mutex на основе примера в этом другом посте.
Код:
map<std::string, double> collection;
mutable boost::shared_mutex collectionMutex;
...
//Write function:
void mapData()
{
// get upgradable access
boost::upgrade_lock<boost::shared_mutex> lock(collectionMutex);
// get exclusive access
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
// Assignments here. Eg:
// collection["Some String"] = 0.0;
}
// Read function:
double readData(std::string name) const
{
double result = 0;
boost::shared_lock<boost::shared_mutex> lock(collectionMutex);
map<std::string, double>::const_iterator it = collection.find(name);
if(it != data.end())
{
result = it->second;
}
return result;
}
Других решений пока нет …