2010-11-17 142 views
7

我有多个线程修改一个stl向量和一个stl列表。
我想避免如果容器为空需要锁定STL是否为空()线程安全?

下面的代码是线程安全吗?如果项目是一个列表或地图呢?

class A 
{ 
    vector<int> items 
    void DoStuff() 
    { 
     if(!items.empty()) 
     { 
      AquireLock(); 
      DoStuffWithItems(); 
      ReleaseLock(); 
     } 
    } 
} 
+0

感谢您的回复。为了澄清这个问题: 另一个线程将添加到项目。没有其他线程将从项目中删除 - 删除将只发生在DoStuffWithItems()内部,并且只有一个线程调用DoStuff()。 好吧,如果items.empty()在另一个线程添加到它时返回false。它不好,如果items.empty()导致应用程序崩溃,如果另一个线程添加到它 – 2010-11-17 15:15:53

回答

6

这取决于你所期望的。其他答案是正确的,一般,标准C++容器不是线程安全的,此外,那特别是你的代码不会阻止另一个线程修改你的调用empty之间的容器和收购锁(但这件事与vector::empty的线程安全无关)。

因此,为了避免任何误解:您的代码并不保证items将在块内非空。

但你的代码仍然是有用的,因为所有你想要做的是避免多余的锁创建。你的代码不能保证,但它可以可能防止不必要的锁创建。它不会工作在所有情况下(其他线程仍然可以清空您的支票和锁之间的容器),但在一些箱子。如果你只想通过省略多余的锁来优化,那么你的代码就完成了这个目标。

只要确保任何实际的访问到容器受锁保护。

顺便说一句,上面是严格地说未定义行为:一个STL实现理论上允许修改调用内部mutable成员empty。这将意味着,显然是无害的(因为只读)调用empty可以实际上会导致冲突。不幸的是,你不能依赖于只读调用与STL容器安全的假设。

但在实践中,我敢肯定,vector::empty修改任何成员。但已经为list::empty我不太确定。如果你真的想保证,那么要么锁访问或不要使用STL容器。

1

STL不是线程安全的,也是空的。如果你想使容器安全必须通过关闭互斥锁或其他同步

3

有在容器和STL中的算法没有任何线程安全保证所有的方法。

所以,第

2

不管是否不为空是线程安全的,你的代码不会,因为写的,实现你的目标。

class A 
{ 
    vector<int> items 
    void DoStuff() 
    { 
     if(!items.empty()) 
     { 
      //Another thread deletes items here. 
      AquireLock(); 
      DoStuffWithItems(); 
      ReleaseLock(); 
     } 
    } 
} 

更好的解决方案是在每次使用items工作时间锁定(迭代时,得到的项目,增加项目,检查计数/空虚,等等),从而提供了自己的线程安全。因此,首先获取锁,然后然后检查向量是否为空。

+0

你的观点(/ /另一个线程删除项目在这里。然而,显然你可以在获得锁后检查empty()以便确定。 – 2010-11-17 14:43:04

+0

@skwllsp:一个有效的观点。如果'empty()'是线程安全的,首先检查空,锁定,然后重新检查可以避免不必要的锁定。 – Brian 2010-11-17 16:03:29

0

因为它已经回答了,上面的代码不是线程安全的,锁定在实际上对容器做任何事情之前是强制性的。 但以下应该比总是锁定有更好的表现,我想不出一个可能是不安全的原因。 这里的想法是,锁定可能是昂贵的,我们正在避免它,只要不是真的需要。

class A 
{ 
    vector<int> items; 
    void DoStuff() 
    { 
     if(!items.empty()) 
     { 
      AquireLock(); 
      if(!items.empty()) 
      { 
       DoStuffWithItems(); 
      } 
      ReleaseLock(); 
     } 
    } 
}