C ++内存模型是否提供有关构造函数操作的保证 [英] Does the C++ memory model provide guarantees about the operations of constructors

查看:67
本文介绍了C ++内存模型是否提供有关构造函数操作的保证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何确保新构造的不可变对象在C ++中的线程之间可以安全共享? C ++内存模型是否提供有关构造函数操作的保证?

How do you ensure newly constructed immutable objects are safely shareable amongst threads in C++? Does the C++ memory model provide guarantees about the operations of constructors?

当您有多个线程共享对一个对象的访问权限,并且修改了该对象时,可能会发生竞争危险.通过将对象安全地发布到所有线程(包括所有可能的将来的线程)可以避免这些问题,因此从任何线程对该对象的所有后续访问都将看到相同的对象状态,然后避免修改该对象.随后访问该对象将不受竞争危险的影响,而无需使用锁(互斥体).在极端情况下,对象是 immutable :一旦构建,就永远不会改变.因此,在多线程程序中要尽可能多地使用不可变对象.

When you have multiple threads that share access to an object, and the object is modified, race hazards are possible. Those problems can be avoided by safely publishing the object to all threads (including all possible future threads), so all subsequent accesses to the object from any thread see the same object state, then refraining from modifying the object. Subsequent accesses to the object will be immune to race hazards without using locks (mutexes). In the extreme case, the object is immutable: once constructed, it is never changed. There is therefore an idiom of using immutable objects as much as possible in multi-threaded programs.

在构造函数中的代码执行后,仍然需要安全地发布对象.构造函数执行的代码将值分配给内存位置,但是这些写入的值可能(最初)仅存在于CPU的本地缓存中.访问这些内存位置的其他线程可能会看到在这些内存位置记录的旧值(例如,由malloc设置的0x00字节模式).对于新构造的对象覆盖的内存位置,必须有一种机制可以刷新本地缓存并使其他CPUS的缓存无效.

That still leaves the need to safely publishing the object after code in the constructor has executed. The code executed by the constructor assigns values to memory locations, but those written values might (initially) exist only in the local cache of the CPU, for example. Other threads that accessed those memory locations might see old values that were recorded at those memory locations (such as a pattern of 0x00 bytes set up by malloc, for example). There must be a mechanism to flush the local cache and invalidate the caches of the other CPUS, for the memory locations covered by the newly constructed object.

在对高级可移植编程语​​言(如C ++)进行编程时,您不必担心缓存和缓存刷新的细节.相反,该语言提供了一组保证(内存模型),并且您必须根据一些惯用法编写代码才能可靠地实现您的目标.

When programming a high level portable programming language, like C++, you do not concern yourself with the details of caches and cache flushing. Instead the language provides a set of guarantees (the memory model), and you have to write your code according to some idioms to reliably achieve your objective.

在Java中,这是通过遵循您的类设计中的一些规则自动完成的(自动)(为了简化起见:类似于C ++中的const ),Java内存模型保证可以达到预期的效果.这可以通过在执行构造函数的代码后立即具有一个内存屏障来实现.

In Java, this is automatically done by following some rules in your class design (to over simplify: make everything final, which is somewhat like const in C++), which the Java memory model guarantees will result in the desired effect. This might be implemented by having a memory-barrier immediately after executing the code of the constructor.

这在C ++ 11中如何完成? C ++内存模型是否提供有关构造函数操作的保证,使您能够自动发布新构造的对象?如果是这样,您上课的规则是什么?如果没有,则您必须自己添加一个内存屏障(如

How is this done in C++11? Does the C++ memory model provide guarantees about the operations of constructors, which enable you to automatically publish a newly constructed object? If so, what are the rules for your classes? And if not, and you have to add a memory barrier yourself (as you apparently have to do for .Net), is there is a idiom for efficiently publishing the object after construction?

还是C ++ 11不提供对不可变对象的线程安全无锁访问?您必须使用互斥保护所有对共享对象(无论是否不可变)的访问吗?

Or does C++11 not provide thread-safe lock-free access to immutable objects? Must you guard all access to shared objects (immutable or not) with mutexes?

推荐答案

主要有两种情况:

  1. 在创建对象之后,按顺序创建读取线程
  2. 在创建对象之后,创建读取线程
  1. The creation of the reading thread is ordered-after the creation of the object
  2. The creation of the reading thread is not ordered-after the creation of the object

在情况1中,对对象的读取访问是自动安全的,因为在创建线程本身之后,对线程的读取是有序的.

In case 1, read access to the object is automatically safe because the read in the thread is ordered-after the creation of the thread itself.

在情况2中,您必须以某种方式对读取进行排序,这完全是因为线程创建不提供该顺序.很明显,如果在对象创建之后读取没有排序,那么事情就会出错.

In case 2, you must order the read somehow, exactly because the thread creation doesn't provide the order. And it's fairly obvious that if the read isn't ordered-after the creation of the object, then things go wrong.

您的问题想知道有关CPU缓存之类的详细信息.这是编译器编写者所关心的.您只需要遵守C ++排序规则即可.

Your question wonders about details like CPU caches. That's a concern for compiler writers. You just need to obey the C++ ordering rules.

这篇关于C ++内存模型是否提供有关构造函数操作的保证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆