使STL对象线程安全的标准方法?

时间:2011-06-05 18:51:18

标签: c++ multithreading stl thread-safety

我需要几个STL容器,线程安全。

基本上我认为我只需要为每个STL容器对象添加2个方法,

.lock()

.unlock()

我也可以将其分解为

.lockForReading()
.unlockForReading()
.lockForWriting()
.unlockForWriting()

可行的方法是可以接受任意数量的并行读取锁,但如果有写入锁,则会阻止读取和写入。

尝试锁定写入等待直到lockForReading信号量降为0。

有没有一种标准方法可以做到这一点?

我是如何计划做错的或短视的?

4 个答案:

答案 0 :(得分:6)

执行此操作的标准方法是获取构造函数中的锁,并在析构函数中释放它。这通常称为资源获取初始化或RAII。我强烈建议你使用这种方法而不是

.lock()

.unlock()

这不是例外安全。您可以在投掷之前轻易忘记解锁互斥锁,从而在下次尝试锁定时导致死锁。

Boost.Thread库中有几种同步类型对您有用,notably boost::mutex::scoped_lock.而不是将lock()unlock()方法添加到任何容器中希望从多个线程访问,我建议您使用boost:mutex或等效的,并在访问容器时实例化boost::mutex::scoped_lock

答案 1 :(得分:6)

这真的很糟糕。外部代码无法识别或理解您的线程语义,容器中对象的别名易用性使它们成为可靠的线程安全接口。

线程安全发生在设计时间。你不能通过在问题上抛出锁来解决线程安全问题。通过不让两个线程同时写入相同的数据来解决线程安全问题 - 当然,在一般情况下。但是,除了直接线程同步原语之外,是处理线程安全的特定对象的责任。

可以拥有并发容器,旨在允许并发使用。但是,它们的接口与标准容器提供的接口差不多。例如,容器中对象的别名较少,并且每个单独的操作都被封装。

答案 2 :(得分:2)

  

有没有一种标准方法可以做到这一点?

不,这是有原因的。

  

我是如何计划这样做的   错误或短视?

想要同步对单个容器对象的访问并不一定是错的,但是容器类的接口 通常是放置同步的错误位置(like DeadMG says:object别名等。)。

就我个人而言,我认为TBBconcurrent_vector这样的内容可能是过度杀戮,或者仍然是“简单”同步问题的错误工具。

我发现,有时只是添加一个(私有)Lock对象(到容纳容器的类),并将2或3个访问模式包装到一个容器对象就足够了,并且对于其他人来说将更容易掌握和维护在路上。

答案 3 :(得分:-1)

Sam:您不希望使用.lock()方法,因为某些内容可能会出错,导致阻止在阻止结束时调用.unlock()方法,但如果.unlock()被称为堆栈分配变量的对象破坏的结果,然后从调用.lock()的函数的任何类型的早期返回将被保证释放锁。

DeadMG: 英特尔的Threading Building Blocksopen source)可能正是您所寻找的。

还有Microsoft's concurrent_vector and concurrent_queue,Visual Studio 2010已经附带。