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

Java C++;内存模型为构造函数的操作提供了保证 如何确保新构造的不可变对象在C++中的线程之间安全共享?C++内存模型是否为构造者提供了保证?,java,c++,multithreading,immutability,Java,C++,Multithreading,Immutability,当您有多个线程共享对某个对象的访问权限,并且该对象被修改时,可能存在争用危险。可以通过将对象安全地发布到所有线程(包括所有可能的未来线程)来避免这些问题,因此任何线程对对象的所有后续访问都会看到相同的对象状态,然后避免修改对象。不使用锁(互斥锁)的情况下,对对象的后续访问将不会受到竞争危险的影响。在极端情况下,对象是:一旦构建,它就永远不会更改。因此,在多线程程序中有一种习惯用法,即尽可能多地使用不可变对象 这仍然需要在构造函数中的代码执行后安全地发布对象。构造函数执行的代码将值分配给内存位置,

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

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

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

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

这在C++11中是如何实现的?C++内存模型是否提供了对构造函数操作的保证,使您能够自动发布新构建的对象?如果是这样,你的课程规则是什么?如果没有,您必须自己添加一个内存障碍(as),是否有一种在构建后高效发布对象的习惯用法


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

主要有两种情况:

  • 读取线程的创建顺序在对象创建之后
  • 在对象创建之后,读取线程的创建不是有序的
  • 在案例1中,对对象的读取访问是自动安全的,因为线程中的读取是在创建线程本身之后排序的


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


    你的问题想知道CPU缓存之类的细节。这是编译器编写人员关心的问题。你只需要遵守C++排序规则。

    可能相关的阅读:C++不允许对象修改,同时从不同线程访问同一对象。其他一切都是公平的。如果没有人更改对象,每个人都可以安全地访问它。显然,在构造对象时,从不同线程访问它是与@n.m相关的一个禁忌。你说的“不允许”是什么意思-据我所知,没有语言机制阻止你这么做-这只是阅读的未定义行为thread@R2RT这意味着执行此操作的程序的行为是未定义的。它还意味着什么呢?“在案例2中,您必须以某种方式对读取进行排序”。是的,但你是怎么做到的?不是在一般情况下,而是在新构造对象的特定情况下?“你只需要遵守C++排序规则”是的,但是这里有什么相关规则?@拉德瓦尔德:C++中有多种机制导致排序关系,它们可以组合(这个排序是传递的,所以A在B和B之前出现,意味着A在C之前)。这给了你很多选择。例如,
    std::mutex
    std::condition\u variable
    都提供了跨线程订购保证。但是C++互斥体没有线程偏好。它通常仅用于防止“并发发生”,而不关心哪个线程首先运行,例如,当您有多个工作线程向
    向量添加值时。那么,您是说构造对象不会引入任何读取顺序(不会自动插入内存屏障),因此,您必须通过引入读取顺序(例如获取和释放互斥)的操作手动跟踪对象的构造。@Raedwald对象构造对于线程来说并不特殊。这只是一系列的访问。“对象构造在任何方面都不是特别的”是至关重要的。