一些语文提供 volatile 修改,被描述为执行了"阅读存储器障碍"之前读取存储器支持的一个变量。

一读存储器障碍通常被描述为的一种方式,以确保CPU已经执行了读取所请求之前的屏障之前执行一读请求后的障碍。然而,使用这一定义,这似乎是一个陈旧的价值仍可以阅读。换句话说,执行读取在一定的秩序似乎并不意味着主存储器或其他的Cpu必须进行咨询,以确保后续读取的值实际上反映最新的系统的时间阅读障碍或随后写入以后阅读障碍。

那么,是否真的挥发性能保证最新的价值是阅读或就(喘气!) 值读,至少作为新的读取之前的障碍?或者一些其他的解释?有什么实际影响的这个答案?

有帮助吗?

解决方案

有阅读障碍和书写的障碍;获取的障碍和释放的障碍。和更多(io vs存储器等)。

障碍是不是有控制"最新的"价值或"新鲜"的价值观。他们在那里控制的相对排序的存储器访问。

写壁垒控制的顺序写入。因为写存是缓慢(相比速度CPU),通常有一个写申请队列里写发布之前他们真的发生'.虽然他们在排队了,而内部队的写可以重新排序。(因此,也许'排队'并不是最好的名字...)除非你使用写信的障碍,以防止重新排序。

阅读障碍控制了读取。因为投机性的执行(CPU看起来之前,并从存储器初)以及因为存在的写入缓冲区(中央处理器会读值写入缓冲区,而不是存,如果它的存在-即CPU认为它只是写X=5,那么为什么阅读回来,看到它仍然在等待 成为 5.在编写缓冲区)读取可能发生的顺序。

这是真实的不管什么样的编译器试图做对了产生的代码。即'挥发性'C++不会帮助在这里,因为它只告诉编译器输出的代码要重新阅读的价值从"存储器",它不告诉CPU如何/何在哪里读它从(即"存储器"是很多东西在CPU水平)。

因此,阅读写障碍放了块防止重新排序在读写队(读通常不是这么多的队列,但重新排序的效果是相同)。

什么样的块?-获取和/或释放块。

获得如读取(x)将增加的读的x入读-队列 和齐平的队列 (不是真的冲队列,但添加标记说不重新排列什么在此之前读取,这是因为如果队列冲洗).以后(在代码为)读取能够重新排序,而不是之前读的x。

释-比如写释(x,5)将flush(或标记)的队列中的第一个,再加入写请求写入队列中。以前写不会成为重新排序发生之后x=5,但请注意,后来写可以被重新排序的前x=5.

注意,我配对的读与获取和编写与释放,因为这是典型,但不同的组合是可能的。

获取和释放被认为是'半的障碍"或"半围栏',因为他们只有停止重新排序从一种方式。

一个全部屏障(或完全围栏)适用于两个获取和释放即没有重新排序。

通常对无锁编程或C#或java'挥发性',你想要的/需要的是 读获取和注释放。

void threadA()
{
   foo->x = 10;
   foo->y = 11;
   foo->z = 12;
   write_release(foo->ready, true);
   bar = 13;
}
void threadB()
{
   w = some_global;
   ready = read_acquire(foo->ready);
   if (ready)
   {
      q = w * foo->x * foo->y * foo->z;
   }
   else
       calculate_pi();
}

因此,首先,这是一个不好的方式来计划的螺纹。锁定将是更加安全。但只是为了说明的障碍...

后threadA()完成编写foo,它需要写foo->准备去的,真的,最后,还有其他线可能会看到foo->初准备就绪和得到错误的价值观的x/y/z。因此,我们使用 write_release 在foo->准备,其中,如上所述,有效的'冲'的写队(确保x、y、z承诺)之后增添的准备=true请求的队列。然后添加bar=13的请求。注意,因为我们只是使用一个释放垒(不是全部)bar=13日获得书面前做好准备。但是,我们不在乎!即我们假设酒吧是不会改变共享数据。

现在马()需要知道,当我们说的"准备就绪"我们真的意味着做好准备。所以我们做一个 read_acquire(foo->ready).这一读取加入读排队,然后排队是刷新。注意, w = some_global 也可以仍然是在队列中。所以foo->准备可能被读取 之前 some_global.但是,我们不关心,因为它不是部分的重要数据,我们就是这么小心。我们做什么关心的是foo->x/y/z。所以他们加入读队之后获得冲/标记,保证他们只读读后foo->准备。

还注意到,这通常是完全相同的障碍用于锁定和一个互斥/CriticalSection/等。(即获得上锁(),释放在解()).

所以,

  • 我很确定这个(即获取/释放)正是MS docs说发生的读写的挥发性'的变量在C#(和任选为MS C++,但这是非标准)。看看 http://msdn.microsoft.com/en-us/library/aa645755(VS。71).aspx 其中包括"挥发性读拥有"获得的语义";也就是说,它是保证之前发生的任何引用的存储器之后发生了..."

  • 想想 java是相同的,尽管我不熟悉。我怀疑它是完全一样,因为你只是通常不需要更多的保证于读取得/写释放。

  • 在你的问题你是在正确的轨道时,认为它是真的所有有关的相对了-你只是有顺序倒退(即"价值观,是阅读,至少作为新的读取之前的障碍?"-不,读取之前阻挡不重要的是,它读之后的障碍,保证之后,反之亦然写).

  • 并请注意,如前所述,重新排序上发生读和写,因此只有采用阻挡在一个线程,而不是其他会无法工作。即一个注释是不够的,而不读获得。即即使你写它的正确顺序,这可能是读错了如果你没有使用的阅读障碍去写的障碍。

  • 最后,请注意,无锁编程和CPU存储架构,可以实际上要复杂得多,但是坚持与获取/发布会得到你非常远。

其他提示

volatile在大多数编程语言并不意味着真实CPU读取存储器屏障而是为了编译器不优化经由缓存在寄存器中读取。这意味着,读取进程/线程将获得值“最终”。一种常用技术是声明一个布尔volatile标志在信号处理程序中设置,并在程序主循环检查。搜索结果 相比之下CPU通过CPU的指令被直接提供存储器障碍之一或与某些汇编助记符隐含(如lock前缀中的x86)和交谈的硬件设备,其中的顺序读取和写入到存储器映射的IO寄存器是重要的,当用于例如或在多处理环境中同步存储器访问。搜索结果 要回答你的问题 - 不,内存屏障不保证“最新”的价值,但担保的订单的内存存取操作。这是例如在无锁编程的关键。搜索结果 这里是在CPU内存屏障物之一。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top