Предположите, что у меня есть ориентированный на многопотоковое исполнение набор Вещей (назовите его 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 блокирует/разблокирует объект, упростил бы/удалил бы пробование/ловление/разблокировать, но для вызывающей стороны все еще легко забыть.
Существует несколько альтернатив, на которые я посмотрел:
ThingList::setItemBar(string name, int value)
- прекрасный, но они имеют тенденцию распространятьсяЧто правильный подход к контакту с этим?
Не существует единого «правильного подхода»; это зависит от потребностей вашего приложения.
Если возможно, возвращайте объекты по значению или возвращайте копию, с которой вызывающий может делать все, что захочет.
Вариант вышеизложенного - вернуть изменяемую копию, а затем предоставить способ атомарного слияния измененного объекта обратно в список. Что-то вроде:
Thing t = myThingList.getThing(key);
t.setFoo(f);
t.setBar(b);
myThingList.merge(t); // ThingList atomically updates the appropriate element
Однако это может вызвать проблемы, если несколько потоков попытаются обновить один и тот же объект.
Идея «похожего на указатель объекта» звучит круто, но я подозреваю, что это приведет к труднодоступным ошибкам, если где-то не снимается какая-то блокировка.
Я бы попытался сохранить весь код блокировки / разблокировки в ThingList
, поэтому функции ThingList :: set ...
, вероятно, я бы сделал.
сохранить и вернуть boost :: shared_ptr s
вы должны заблокировать во время доступа, но вы в безопасности после разблокировки