如何确保在C++中新构造的不可变对象在线程之间安全共享?C++内存模型是否提供有关构造函数操作的保证?
当您有多个共享访问对象的线程,并且对象被修改时,可能会出现竞争条件。可以通过将对象“安全发布”到所有线程(包括所有可能的未来线程),以便从任何线程对对象的所有后续访问看到相同的对象状态,然后避免修改对象来避免这些问题。在没有使用锁(互斥体)的情况下,后续对对象的访问将不受竞争条件的影响。在极端情况下,该对象是不可变的:一旦构造,就不再改变。因此,在多线程程序中尽可能地使用不可变对象的习惯用法存在。
这仍然需要在构造函数执行代码后安全地发布对象。构造函数执行的代码将值分配给内存位置,但这些写入的值可能(最初)仅存在于CPU的本地缓存中。其他访问这些内存位置的线程可能会看到旧值,这些旧值记录在这些内存位置上(例如,由
当使用高级便携式编程语言(如C ++)进行编程时,您不必关心缓存和缓存刷新的详细信息。相反,该语言提供了一组保证(内存模型),您必须根据某些习惯用法编写代码以可靠地实现您的目标。
在Java中,这是通过遵循类设计中的一些规则(简化来说:使所有内容
在C++11中如何实现呢?C++内存模型是否提供有关构造函数操作的保证,使您能够自动发布新构造的对象?如果是这样,那么您类的规则是什么?如果不是,而且您必须自己添加内存屏障(就像.Net一样),那么是否有一种习惯用法可以在构造后高效地发布对象?
或者C++11没有提供对不可变对象的线程安全无锁访问?必须使用互斥锁来保护对共享对象(不管是不是不可变的)的所有访问吗?
当您有多个共享访问对象的线程,并且对象被修改时,可能会出现竞争条件。可以通过将对象“安全发布”到所有线程(包括所有可能的未来线程),以便从任何线程对对象的所有后续访问看到相同的对象状态,然后避免修改对象来避免这些问题。在没有使用锁(互斥体)的情况下,后续对对象的访问将不受竞争条件的影响。在极端情况下,该对象是不可变的:一旦构造,就不再改变。因此,在多线程程序中尽可能地使用不可变对象的习惯用法存在。
这仍然需要在构造函数执行代码后安全地发布对象。构造函数执行的代码将值分配给内存位置,但这些写入的值可能(最初)仅存在于CPU的本地缓存中。其他访问这些内存位置的线程可能会看到旧值,这些旧值记录在这些内存位置上(例如,由
malloc
设置的0x00字节模式)。必须有一种机制来刷新本地缓存并使其他CPU的缓存失效,以覆盖新构造的对象所涵盖的内存位置。当使用高级便携式编程语言(如C ++)进行编程时,您不必关心缓存和缓存刷新的详细信息。相反,该语言提供了一组保证(内存模型),您必须根据某些习惯用法编写代码以可靠地实现您的目标。
在Java中,这是通过遵循类设计中的一些规则(简化来说:使所有内容
final
,这有点像C++中的const
)自动完成的,Java内存模型保证会产生期望的效果。这可能是通过在构造函数代码执行后立即设置内存屏障来实现的。在C++11中如何实现呢?C++内存模型是否提供有关构造函数操作的保证,使您能够自动发布新构造的对象?如果是这样,那么您类的规则是什么?如果不是,而且您必须自己添加内存屏障(就像.Net一样),那么是否有一种习惯用法可以在构造后高效地发布对象?
或者C++11没有提供对不可变对象的线程安全无锁访问?必须使用互斥锁来保护对共享对象(不管是不是不可变的)的所有访问吗?