C++ 硬件级。Visual Studio 2010和Visual Studio 2008的MSDN文档明确否认编译器内部函数适用于硬件级别:

C++ 硬件级。Visual Studio 2010和Visual Studio 2008的MSDN文档明确否认编译器内部函数适用于硬件级别:,c++,multithreading,concurrency,atomic,memory-barriers,C++,Multithreading,Concurrency,Atomic,Memory Barriers,_ReadBarrier、_WriteBarrier和_ReadWriteBarrier编译器内部函数仅阻止编译器重新排序。要防止CPU对读写操作重新排序,请使用MemoryBarrier宏 VisualStudio2005和VisualStudio.NET2003的MSDN文档中没有这样的注释。它没有说明内部函数是否适用于硬件级别 如果_ReadBarrier和_WriteBarrier确实没有实施硬件防护,则代码不正确 关于“篱笆”一词 Joe Duffy在他的书中使用术语围栏来表示硬件和内

_ReadBarrier、_WriteBarrier和_ReadWriteBarrier编译器内部函数仅阻止编译器重新排序。要防止CPU对读写操作重新排序,请使用MemoryBarrier宏

VisualStudio2005和VisualStudio.NET2003的MSDN文档中没有这样的注释。它没有说明内部函数是否适用于硬件级别

如果_ReadBarrier和_WriteBarrier确实没有实施硬件防护,则代码不正确

关于“篱笆”一词 Joe Duffy在他的书中使用术语围栏来表示硬件和内存围栏。在511页,他写道:

栅栏也常被称为屏障。英特尔似乎更喜欢“围栏”这个术语,而AMD更喜欢“屏障”。我也更喜欢“围栏”,所以这就是我在本书中使用的

五金栅栏 我相信硬件围栏也有隐式编译障碍(禁用编译优化)

本文确认硬件障碍也会影响编译器:

这些指令(内存屏障)还确保编译器禁用任何可能跨屏障重新排序内存操作的优化

但是,的MSDN文档表明,并不总是阻止编译器重新排序:

创建硬件内存屏障(围栏),防止CPU重新排序读写操作。它还可以防止编译器对读写操作重新排序


事实上,我不明白如果编译器可以重新排序围绕它的内存操作,如何使用硬件围栏。我们无法确定围栏是否位于正确的位置。

如果围栏位于库中,则它已被编译。图书馆是链接的。对,这是我错过的。那么阅读障碍的目的是什么呢?老实说,我不确定。我没有看到调用函数的线程的挂起内存读取。(请参阅)存在读取屏障以防止硬件重新排序。考虑C++代码GETValueE()->弱序硬件可能会在调用getValue()之前推测性地加载f,如果getValue()采用其隐式的“else”路径,那么如果没有读屏障,硬件就没有理由重新加载f。@ArchD.Robison,听起来很合理。但是,ReadBarrier是编译屏障,它如何防止处理器执行无序?编译障碍也意味着隐含的硬件围栏吗?我对硬件重新排序的看法是错误的。清楚地表明_ReadBarrier只阻止编译器重新排序,而不阻止硬件重新排序。一般来说,仅编译器的屏障出于这个原因是无用的,除了涉及线程和同一线程上的信号处理程序之间的争用的情况。因此,原来的示例实际上在具有弱有序内存一致性的硬件(例如安腾或Arm)上被破坏。
T getValue(){
    if (!m_pValue){
        EnterCriticalSection(&m_crst);
        if (! m_pValue){
            T pValue = m_pFactory();
            _WriteBarrier();
            m_pValue = pValue;                  
        }
        LeaveCriticalSection(&m_crst);
    }
      _ReadBarrier();
  return m_pValue;
}
int* pValue = new int(42);
m_pValue = pValue;         
//m_pValue now points to anewly allocated int with value 42.
int* pTmp = new int;
*pTmp = 42;
int* pValue = *pTmp;
int* pTmp = new int;
int* pValue = *pTmp;
m_pValue = pValue;  
*pTmp = 42;
//m_pValue now points to a newly allocated int with value 42.
m_pValue = new int;  
*m_pValue = 42;
//m_pValue now points to a newly allocated int with value 42.
m_pValue = new int;  
*m_pValue = 42;
LeaveCriticalSection();
Thread 1:                | Thread 2:
                         |
m_pValue = new int;      | 
                         | if (!m_pValue){     //already false
                         | }
                         | return m_pValue;
                         | /*use *m_pValue */
*m_pValue = 42;          |
LeaveCriticalSection();  |