Возврат указателей потокобезопасным способом - PullRequest
6 голосов
/ 20 апреля 2010

Предположим, у меня есть потокобезопасная коллекция вещей (назовите ее ThingList), и я хочу добавить следующую функцию.

Thing * ThingList::findByName(string name)
{
  return &item[name]; // or something similar..
}

Но, сделав это, я делегировал ответственность за безопасность потоков вызывающему коду, который должен был бы сделать что-то вроде этого:

try 
{
  list.lock(); // NEEDED FOR THREAD SAFETY
  Thing *foo = list.findByName("wibble");
  foo->Bar = 123;
  list.unlock();  
}
catch (...) 
{
  list.unlock();
  throw;
} 

Очевидно, что объект блокировки / разблокировки RAII упростит / удалит try / catch / unlocks, но вызывающему все равно легко забыть.

Я рассмотрел несколько альтернатив:

  • Возвращать Вещи по значению вместо указатель - хорошо, если вам не нужно изменить вещь
  • Добавить функцию ThingList::setItemBar(string name, int value) - хорошо, но они, как правило, пролиферируют
  • Возвращает объект, похожий на указатель, который блокирует список при создании и снова разблокирует его при уничтожении. Не уверен, что это хорошая / плохая практика ...

Какой правильный подход к решению этой проблемы?

Ответы [ 2 ]

4 голосов
/ 20 апреля 2010

Нет единого «правильного подхода»; это зависит от потребностей вашего приложения.

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

Вариант вышеупомянутого - вернуть изменяемую копию, а затем предоставить способ атомарного объединения измененного объекта обратно в список. Что-то вроде:

Thing t = myThingList.getThing(key);
t.setFoo(f);
t.setBar(b);
myThingList.merge(t);     // ThingList atomically updates the appropriate element

Однако это может вызвать проблемы, если несколько потоков пытаются обновить один и тот же объект.

Идея "объекта в виде указателя" звучит круто, но я подозреваю, что это приведет к трудно обнаруживаемым ошибкам, когда какая-то блокировка не будет снята где-то.

Я бы постарался сохранить весь код блокировки / разблокировки в пределах ThingList, поэтому функции ThingList::set..., вероятно, будут такими же, как и я.

3 голосов
/ 20 апреля 2010

store и return boost :: shared_ptr s

вы должны заблокировать доступ, но после разблокировки вы в безопасности.

...