当前位置: 首页 > 知识库问答 >
问题:

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

郦良才
2023-03-14

使用std::forward_list擦除和插入时是否存在数据争用?例如,我有一个线程只在列表末尾添加新元素,而另一个线程遍历(相同)列表并可以从中删除元素。

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

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

共有3个答案

梅耘豪
2023-03-14

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

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

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

毛声
2023-03-14

否,无论是forward_list还是任何其他STL容器对于写入都是线程安全的。您必须提供同步,以便在写入发生时没有其他线程对容器进行读取或写入。只有同时读取才是安全的。

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

金赤岩
2023-03-14

标准C库容器有线程安全保证,但它们往往不是人们会考虑线程安全保证(即,人们期望错误的错误)。标准库容器的线程安全保证大致如下(相关第17.6.5.9节[res.on.data.races]):

  1. 您可以拥有任意数量的容器读取器。什么是真正合格的阅读器是有点微妙,但大致相当于用户的const成员函数加上使用一些非const成员只读取数据(线程安全的读取数据不是任何容器关心,即23.2.2[container.requirements.dataraces]指定可以在容器不引入数据竞争的情况下更改元素)。
  2. 如果一个容器只有一个写入器,则在另一个线程中不得有其他读取器或写入器。

也就是说,读取容器的一端并写入另一端不是线程安全的!事实上,即使实际的容器更改不会立即影响读取器,在将一段数据从一个线程传递到另一个线程时,您始终需要某种形式的同步。也就是说,即使您可以保证使用者不会erase()生产者当前的节点insert()s,也会出现数据竞争。

 类似资料:
  • 我的任务是创建函数来添加和删除链表中的节点,输入数据为int,字符为with函数调用。我不确定我做错了什么。我得到的唯一错误是:退出时返回代码为-11(SIGSEGV)。还有一个编译器方法:main。cpp:在函数“void listInsertValue(ListNode)”中* 感谢任何帮助。谢谢!

  • 我有一个在Oracle 11g DB上运行的insert语句,如下所示: 这里有一个处理PostgreSQL的类似问题。但是,由于Oracle序列由所有会话共享,所以我不能相信DB会给出当前会话中最后插入的值。

  • 我试图编写一个方法来插入一个节点和移除链表后面的一个节点。下面是我在其中编写方法的主类。它们在底部(insertBack和removeBack): 可能有格式错误,因为我粘贴到这里,但我仍然试图找出如何使用这个网站。当我运行如下所示的驱动程序类时,我会得到如下所示的结果。 有人能帮我弄清楚为什么我的removeFront和removeBack方法不起作用吗?

  • 问题内容: 我一直在假设线程安全也不是线程安全,但是在最近的一次讨论中,一位同事告诉我线程安全。 因此,我做了一些研究,却一无所获。很多人认为它是线程安全的,很多人认为它不是线程安全的。而且,最重要的是,文档没有以一种或另一种方式说任何话,不是为了,甚至不是。 那是什么呢? 问题答案: 这是指向Java 7 中Calendar和GregorianCalendar的源代码的链接。 如果阅读该代码,您

  • 我必须编写一个双链接列表,我正在尝试实现方法,该方法接受一个参数obj,遍历列表并删除包含元素obj的每个节点。 我面临的问题是,我从前面遍历链表,当我找到包含obj元素的节点时,我会在包含obj元素的节点前后更改节点的下一个/上一个指针。然而,我并没有删除带有obj本身的节点,据我所知,c没有垃圾收集,所以带有obj的节点仍然悬在空中。我如何删除它? 我的擦除()