c++ 当在一个线程中写入并在第二个线程中读取同一个对象时会发生啥? (它安全吗?)[重复]

Posted

技术标签:

【中文标题】c++ 当在一个线程中写入并在第二个线程中读取同一个对象时会发生啥? (它安全吗?)[重复]【英文标题】:c++ what happens when in one thread write and in second read the same object? (is it safe?) [duplicate]c++ 当在一个线程中写入并在第二个线程中读取同一个对象时会发生什么? (它安全吗?)[重复] 【发布时间】:2018-06-12 09:17:27 【问题描述】:

当在一个线程中写入和在第二个线程中读取同一个对象时会发生什么?会导致应用崩溃?

我的想法是,在主线程上将数据保存到对象或从对象更改数据,而在第二个线程上只读取这些数据。

如果我理解,问题可能只是在写入对象新值并同时从同一个对象读取时,读取值将是旧的。但这对我来说不是问题。

我搜索了我的问题并找到了这个主题What happens if two threads read & write the same piece of memory,但我不确定它是否适用于我的问题。

【问题讨论】:

【参考方案1】:

除非对象是原子的,否则一个线程写入和另一个线程读取同一对象的行为是未定义

您目前认为唯一的问题是可以读取状态数据的看法是不正确的。您不能假设这只是未定义行为的表现。特别是,您很可能会发现您读取的值既不是旧值也不是新值。

【讨论】:

可能值得一提的是,一个特别合理的失败是读取的值既不是旧值也不是新值。但是,根据优化器的不同,代码绝对可以做任何事情。 @MartinBonner 已添加。 @Bathsheba 理解你,如果对象是原子的,那么它会好吗?例如,'std::atomic<:tm> time_object;'在不同线程中同时读取和写入该对象不会导致未定义的行为?我问是因为你的“除非对象是原子的”,可以用我的语言翻译(意思)“如果对象是原子的,行为是未定义的”或“如果对象不是原子的,行为是未定义的”。【参考方案2】:

这实际上取决于您尝试读取和写入的内存块的大小。如果您正在读取单个原子数据类型,那么您只能读取和写入整个内存块(以 int 为例)。您可以不确定地从数据类型中获取新值或旧值,而不会出现任何问题。

如果您正在读取和写入非原子内存块,那么在读取周期中,某些块可能会被覆盖,因此信息可能会被破坏。这会导致一些疯狂的行为,并可能导致中断。

https://en.wikipedia.org/wiki/Linearizability

【讨论】:

int 是原子的隐藏假设非常顽皮。 是的,我觉得不好说但是google.co.uk/… 您也忘记了缓存一致性问题。例如,在 ARM 上,一个内核可以在循环中写入一个值,而另一个内核可以读取一个值并等待它在循环中更改并且永远不会看到更改。写入始终进入 L1 缓存,并且永远不会被其他核心缓存刷新和看到。【参考方案3】:

这不安全。考虑使用互斥锁来避免内存损坏:

http://en.cppreference.com/w/cpp/thread/mutex

【讨论】:

【参考方案4】:

通常结果是未定义的。你必须做一些事情来定义它,并且你有很多文档要阅读。

    编译器必须知道它下面的值可能会被更改。否则优化器会做错事,写操作会被完全忽略。这里的关键字是volatile。当变量从信号处理程序或硬件本身更改时,这是必需的。不足以支持多线程。

    您必须确保读取和写入不会中断。一种方法是使用原子类型。另一种是使用锁或互斥锁来保护对变量的访问。原子类型的大小受硬件支持的限制,因此除了简单的整数或单指针之外的任何东西都需要锁。 std::atomic 类型将其抽象出来。它知道哪些类型在您的硬件上是原子的,以及何时需要使用锁定。

    即使这样还不够,因为读取和写入的时间仍然是随机的。如果一个线程写入而另一个线程读取它将读取什么?第二个线程会在第一次写入之前还是之后读取?即使正确使用原子或锁,您也不知道天气,您将获得旧值或新值。如果这很重要,您必须在线程之间进行同步,以便定义读取和写入的顺序。寻找条件。

【讨论】:

volatile 在 C++ 中非常有用,如果您处理的内存映射硬件可能会因为发生的事情而发生变化。在处理多线程 C++ 时几乎没有使用。 std::atomic 也适用于任何可简单复制的类型(尽管如果类型太大,它内部会有一个互斥锁)。 volatile 不用于多线程 Volatile and multithreading: Is the following thread-safe?

以上是关于c++ 当在一个线程中写入并在第二个线程中读取同一个对象时会发生啥? (它安全吗?)[重复]的主要内容,如果未能解决你的问题,请参考以下文章

Libevent 仅在第二个 buffer_write 之后写入套接字

在 C 或 C++ 中的同一个套接字上同时读取和写入

在同一页面中使用两个 BLoC 并在第二个 BLoC 中传递第一个 BLoC 的状态

在第二个线程中显示图像,OpenCV?

关于 c++ 初始化程序的内存一致性

我正在尝试在第二个线程中向自身添加一个 int 并且我的主线程中没有任何变化