是 C++ std::set 线程安全?

发布于 2024-08-04 02:30:17 字数 220 浏览 7 评论 0原文

我对 std::set 的线程安全有疑问。

据我所知,我可以迭代一个集合并添加/删除成员,这不会使迭代器无效。

但请考虑以下场景:

  • 线程“A”迭代一组shared_ptr
  • 线程“B”偶尔会向该集合添加项目。

我在程序运行时遇到了段错误,但我不确定为什么会发生这种情况。缺乏线程安全是原因吗?

I've a question about the thread safety of std::set.

As far as I know I can iterate over a set and add/erase members and that doesn't invalidate the iterators.

But consider following scenario:

  • thread 'A' iterates over a set of shared_ptr<Type>
  • thread 'B' occasionally adds items to this set.

I've experienced segfaults as the program runs and I'm not sure why this happens. Is lack of thread safety the cause?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

油饼 2024-08-11 02:30:17

STL 没有内置线程支持,因此您必须扩展 STL
使用您自己的同步机制编写代码以在中使用STL
多线程环境。

例如,请查看此处:链接文本

由于set是一个容器类,MSDN对容器的线程安全有如下说法。

单个对象对于从多个线程读取是线程安全的。例如,给定一个对象 A,同时从线程 1 和线程 2 读取 A 是安全的。

如果一个线程正在写入单个对象,则同一线程或其他线程上对该对象的所有读取和写入都必须受到保护。例如,给定一个对象 A,如果线程 1 正在写入 A,则必须阻止线程 2 读取或写入 A。

即使另一个线程正在读取或写入某一类型的一个实例,读取和写入也是安全的。写入同一类型的不同实例。例如,给定相同类型的对象 A 和 B,如果 A 在线程 1 中写入,B 在线程 2 中读取,则这是安全的。

STL has no built in thread support, so you'll have to extend the STL
code with your own synchronization mechanisms to use STL in
a multithreaded environment.

For example look here: link text

Since set is a container class MSDN has following to say about the thread safety of the containers.

A single object is thread safe for reading from multiple threads. For example, given an object A, it is safe to read A from thread 1 and from thread 2 simultaneously.

If a single object is being written to by one thread, then all reads and writes to that object on the same or other threads must be protected. For example, given an object A, if thread 1 is writing to A, then thread 2 must be prevented from reading from or writing to A.

It is safe to read and write to one instance of a type even if another thread is reading or writing to a different instance of the same type. For example, given objects A and B of the same type, it is safe if A is being written in thread 1 and B is being read in thread 2.

二智少女 2024-08-11 02:30:17

Dinkumware STL 文档包含有关该主题的以下段落。它可能(如文本中所示)对于大多数实现都有效。

对于定义在的容器对象
标准 C++ 库,例如 STL
模板的容器和对象
类 basic_string,这个
实施遵循广泛
SGI 所采用的做法
STL:

多个线程可以安全地读取同一个容器对象。 (有
内不受保护的可变子对象
一个容器对象。)

两个线程可以安全地操作不同的容器对象
属于同一类型。 (没有
不受保护的共享静态对象
在容器类型内。)

您必须防止同时访问容器
对象,如果至少有一个线程
修改对象。 (显而易见的
同步原语,例如
那些在 Dinkum Threads 库中的,
不会被容器颠覆
对象。)

因此,没有尝试确保
容器上的原子操作
对象是线程安全的;但它是
很容易制作共享容器
线程安全的对象
适当的粒度级别。

The Dinkumware STL-Documentation contains the follwing paragraph about that topic. Its probably (as indicated in the text) valid for most implementations.

For the container objects defined in
the Standard C++ Library, such as STL
Containers and objects of template
class basic_string, this
implementation follows the widely
adopted practices spelled out for SGI
STL:

Multiple threads can safely read the same container object. (There are
nunprotected mutable subobjects within
a container object.)

Two threads can safely manipulate different container objects
of the same type. (There are no
unprotected shared static objects
within a container type.)

You must protect against simultaneous access to a container
object if at least one thread is
modifying the object. (The obvious
synchronization primitives, such as
those in the Dinkum Threads Library,
will not be subverted by the container
object.)

Thus, no attempt is made to ensure
that atomic operations on container
objects are thread safe; but it is
easy enough to make shared container
objects that are thread safe at the
appropriate level of granularity.

み青杉依旧 2024-08-11 02:30:17

没有一个 STL 容器是线程安全的,所以 std::set 尤其不是。

在您的情况下,问题甚至不是真正的线程安全:您只需在多个线程之间共享一个对象(很好)并在一个线程中修改它(也很好)。但正如您已经说过的,修改容器会使其迭代器失效。无论这种情况发生在同一个线程中还是不同的线程中,都没有什么影响,因为它仍然同一个容器

天啊! §23.1.2.8 规定插入不会使迭代器失效。

None of the STL containers is thread safe, so std::set in particular isn’t.

In your case, the issue isn’t even really thread safety, though: You simply share an object across multiple threads (fine) and modify it in one thread (fine as well). But as you’ve already said, modifying the container invalidates its iterators. Whether this happens in the same thread or in a different thread is of no consequence since it’s still the same container.

D'oh! §23.1.2.8 states that inserting doesn’t invalidate iterators.

烂柯人 2024-08-11 02:30:17

简单解释:如果线程 A 在容器中移动迭代器,它就会查看容器内部。如果线程 B 修改容器(即使是一个不会使 A 所具有的迭代器无效的操作),线程 A 可能会遇到麻烦,因为 B 正在欺骗容器内部,可能使它们处于(暂时)无效状态。这会导致线程 A 崩溃。

问题不在于迭代器本身。当他们需要容器的数据结构来找到你遇到麻烦的位置时。

就这么简单。

Simple explanation: If thread A is moving iterators through the container, it's looking at container internals. If thread B modifies the container (even an operation that doesn't invalidate the iterator that A has), thread A can run into trouble because B is fooling with the container internals, possibly having them in a (temporarily) invalid state. This causes crashes in thread A.

The problem ISN'T the iterators themselves. It when they need the container's data structures in order to find the position that you get into trouble.

Simple as that.

苦妄 2024-08-11 02:30:17

执行插入可能会导致向量重新分配其底层内存,而迭代器可能仍指向先前(但无效)的内存地址,从而导致段错误。

Performing an insertion can cause the vector to reallocate its underlying memory while iterator may still point to the previous (but invalid) memory address, leading to segment fault.

っ〆星空下的拥抱 2024-08-11 02:30:17

是的。处理这种情况的一种方法是让每个线程在访问同一个集合对象之前锁定一个共享互斥锁。确保使用 RAII 技术来锁定和解锁互斥体。

Yes. One way to handle this situation is to have each thread lock a shared mutex before accessing the same set object. Make sure you use RAII techniques to lock and unlock the mutex.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文