C ++内存模型是否提供有关构造函数操作的保证

时间:2017-11-23 16:25:05

标签: java c++ multithreading immutability

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

如果您有多个共享对象访问权限的线程,并且该对象已被修改,则可能存在种族危险。通过将对象安全地发布到所有线程(包括所有可能的未来线程)可以避免这些问题,因此从任何线程对对象的所有后续访问都会看到相同的对象状态,然后避免修改对象。在不使用锁(互斥锁)的情况下,对对象的后续访问将不受种族危害的影响。在极端情况下,对象是immutable:一旦构造,它永远不会改变。因此,在多线程程序中尽可能多地使用不可变对象。

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

编写高级可移植编程语​​言(如C ++)时,您不必关心缓存和缓存刷新的细节。相反,该语言提供了一组保证(内存模型),您必须根据一些习语编写代码,以可靠地实现您的目标。

在Java中,通过遵循类设计中的一些规则(过度简化:make everything final,即somewhat like const in C++)来完成自动,这是Java内存模型保证将产生预期的效果。这可以通过在执行构造函数的代码之后立即具有内存屏障来实现。

这是如何在C ++ 11中完成的? C ++内存模型是否提供有关构造函数操作的保证,这使您能够自动发布新构造的对象?如果是这样,您的课程规则是什么?如果没有,你必须自己添加一个内存屏障(如you apparently have to do for .Net),是否有一个习惯用于在构建后有效地发布对象?

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

1 个答案:

答案 0 :(得分:0)

主要有两种情况:

  1. 在创建对象
  2. 之后,对读取线程的创建进行了排序
  3. 在创建对象后> 订阅阅读主题的创建
  4. 在案例1中,对对象的读访问权是自动安全的,因为在创建线程本身之后,线程中的读取是有序的。

    在案例2中,您必须以某种方式对读取进行排序,因为线程创建并未提供订单。而且很明显,如果在创建对象之后读取没有排序,那么事情就会出错。

    你的问题想知道像CPU缓存这样的细节。这是编译器编写者的一个问题。您只需要遵守C ++排序规则。