2010-04-19 2 views
6

Предположим, что у меня есть потокобезопасная коллекция вещей (назовите ее 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, но для абонента все же легко забыть.

Есть несколько альтернатив, я посмотрел на:

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

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

ответ

4

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

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

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

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

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

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

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

+0

«Объединить» это хорошо, но есть скрытое предположение, что объекты Thing знают, как найдите себя в списке. Вы также можете передать «ключ» для слияния, но тогда у вас возникла проблема слияния элемента, который был удален ... – Roddy

3

магазин и вернуть повышение :: shared_ptr s

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

+1

boost :: shared_ptr не делает ничего, чтобы защитить безопасность потока коллекции. –

+0

зависит от того, с чем связана проблема безопасности потоков. Вы должны блокировать доступ к коллекции (читать или писать), но вы все равно должны это делать. Возвращая общий ptr, вы, по крайней мере, гарантируете, что если коллекция будет изменена позади вас, вы все равно в порядке (предполагая, что коллекция также является коллекцией shared_ptrs). Это модель, которую я использую все время на многопоточном сервере – pm100

+0

Я не знал, что shared_ptr был потокобезопасным, но, думая об этом, нет причин, которого это не могло быть.Я знаю, что COM Microsoft использует InterlockedIncrement и InterlockedDecrement, чтобы выполнить очень легкую потокобезопасную реализацию. –

 Смежные вопросы

  • Нет связанных вопросов^_^