擦除和插入单个链表线程是否安全?

时间:2014-01-02 16:38:05

标签: c++ linked-list thread-safety singly-linked-list

使用std :: forward_list在删除插入时是否有任何数据争用?例如,我有一个线程除了在列表的末尾添加新元素之外什么都不做,我有另一个线程可以遍历(相同)列表并可以从中删除元素。

根据我所知的链表,每个元素都有一个指向下一个元素的指针,所以如果我擦除最后一个元素,同时我插入一个新元素,这会导致数据竞争还是这些容器的工作方式不同(或者他们是否处理这种可能性)?

如果是数据竞赛,是否有(简单而快速)的方法来避免这种情况? (注意:插入的线程是两者中最关键的速度。)

4 个答案:

答案 0 :(得分:6)

标准C ++库容器有线程安全保证,但它们往往不是人们会考虑线程安全保证的那种(也就是说,人们期待错误的错误)。标准库容器的线程安全保证大致(相关部分17.6.5.9 [res.on.data.races]):

  1. 您可以根据需要拥有尽可能多的容器读者。什么完全符合读者的要求有点巧妙,但大致相当于const成员函数的用户加上使用一些非const成员只读取数据(线程安全)读取数据不是任何容器所关注的,即23.2.2 [container.requirements.dataraces]指定可以在没有容器引入数据竞争的情况下更改元素。)
  2. 如果有一个容器的作者,则容器中没有其他读者或写入另一个帖子。
  3. 也就是说,读取容器的一端并编写另一端是线程安全!实际上,即使实际的容器更改不会立即影响读者,在将一段数据从一个线程传递到另一个线程时,总是需要某种形式的同步。也就是说,即使您可以保证消费者不会erase()生产者当前insert()的节点,也会有数据竞争。

答案 1 :(得分:3)

不,forward_list和任何其他STL容器对于写入都不是线程安全的。您必须提供同步,以便在写入时没有其他线程读取或写入容器。只有同时读取才是安全的。

执行此操作的最简单方法是在发生插入时使用互斥锁锁定对容器的访问。以可移植的方式执行此操作需要C ++ 11(std::mutex)或特定于平台的功能(mutexes in Windows,在Linux / Unix中可能为pthreads

答案 2 :(得分:2)

除非您使用明确声明它是线程安全的STL版本,否则容器不是线程安全的。

默认情况下很少使通用容器线程安全,因为它会对不需要线程安全访问容器的用户造成性能损失,这是迄今为止正常的使用模式。

如果线程安全对您来说是一个问题,那么您需要使用锁定代码,或者使用专为多线程访问而设计的数据结构。

答案 3 :(得分:1)

std容器并不意味着线程安全。

您应该小心保护它们以进行修改操作。