假设我有一个线程安全的Things集合(称之为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)
- 很好,但这些往往
增殖处理这个问题的正确方法是什么?
答案 0 :(得分:4)
没有一个“正确的方法”;这取决于您的应用程序的需求。
如果可能,按值返回内容,或返回调用者可以随意执行的任何副本。
上述的一个变体是返回一个可修改的副本,然后提供一种将修改后的对象原子合并回列表的方法。类似的东西:
Thing t = myThingList.getThing(key);
t.setFoo(f);
t.setBar(b);
myThingList.merge(t); // ThingList atomically updates the appropriate element
但是,如果多个线程尝试更新同一个对象,则会导致问题。
“指针式对象”的想法听起来很酷,但我怀疑当某些锁没有被释放时,它会导致难以发现的错误。
我会尝试将所有锁定/解锁代码保留在ThingList
内,因此ThingList::set...
函数可能就是我要做的。
答案 1 :(得分:3)
存储并返回boost :: shared_ptr s
你必须在访问期间锁定,但解锁后你是安全的