以线程安全的方式返回指针

Rod*_*ddy 6 c++ pointers thread-safety

假设我有一个线程安全的Things集合(称之为ThingList),我想添加以下函数.

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

但通过这样做,我已将线程安全的责任委托给调用代码,该代码必须执行以下操作:

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

显然,RAII锁定/解锁对象会简化/删除try/catch/unlocks,但是调用者仍然很容易忘记.

我看过几个替代方案:

  • 除非你需要修改Thing,否则返回值而不是指针 - 罚款
  • 添加功能ThingList::setItemBar(string name, int value)- 很好,但这些往往会增殖
  • 返回一个指针式对象,它在创建时锁定列表,并在销毁时再次解锁.不确定这是好/坏的做法......

处理这个问题的正确方法是什么?

Kri*_*son 4

没有一种“正确的方法”;这取决于您的应用程序的需求。

如果可能的话,按值返回内容,或者返回一个副本,调用者可以用它做任何他们想做的事情。

上述的一个变体是返回一个可修改的副本,然后提供一种以原子方式将修改后的对象合并回列表中的方法。就像是:

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

但是,如果多个线程尝试更新同一对象,则可能会导致问题。

“类指针对象”的想法听起来很酷,但我怀疑当某些锁没有在某处释放时,它会导致难以发现的错误。

我会尝试将所有锁定/解锁代码保留在 中ThingList,因此这些ThingList::set...功能可能就是我要做的。