while循环与空身体检查挥发性整数 – 这是什么意思?

我正在看一个有以下几行的C ++类:

while( x > y ); return x - y; 

xyvolatile inttypes的成员variables。 我不明白这个构造。

我在这里find代码存根: https : //gist.github.com/r-lyeh/cc50bbed16759a99a226 。 我想这不能保证是正确的,甚至工作。

由于xy已经被声明为volatile,程序员期望他们会从程序之外改变。

在这种情况下,你的代码将保持在循环中

  while(x>y); 

并且在值从外部改变之后将返回值xy ,使得x <= y 。 当你告诉我们更多关于你的代码和你看到它的地方之后,这个写法的确切原因是可以猜到的。 在这种情况下, while循环是一些其他事件发生的等待技巧。

它似乎

 while( x > y ); 

是一个纺纱循环 。 它不会停止,直到x <= y 。 由于xyvolatile ,它们可能会在这个例程之外被改变。 所以,一旦x <= y成立, x - y将被返回。 这个技巧是用来等待一些事件的。

更新

根据您添加的要点 ,似乎想法是实现线程安全的无锁循环缓冲区。 是的,实施是不正确的。 例如,原始的代码片段是

 unsigned count() const { while( tail > head ); return head - tail; } 

即使tail变小或等于head ,也不能保证head - tail返回正数。 调度程序可能会在while循环之后立即将执行切换到另一个线程,并且该线程可能会更改head值。 无论如何,还有很多其他的问题涉及如何读写共享内存工作(内存重新sorting等),所以只是忽略这个代码。

其他的回复已经详细指出了这个指令的作用,但是要回顾一下,由于y (或者在链接的例子中是head )被声明为从不同的线程对该variables进行的volatile变化将导致while循环完成一次病情已经得到满足。

但是,即使链接的代码示例非常短,这也是如何编写代码的完美例子。

首先是线路

 while( tail > head ); 

会浪费大量的CPU周期,几乎locking一个核心,直到满足条件。

随着我们的进展,代码变得更好。

 buffer[head++ % N] = item; 

感谢JAB指出我错误地在这里预增。 更正了影响。 由于没有lockmutex我们显然将不得不承担最坏的情况。 线程将在分配值中的值和在执行head++之前切换。 墨菲将再次调用包含这个语句的函数,在同一个head位置分配item的值。 之后, head增加。 现在我们切换回第一个线程并再次递增。 所以,而不是

 buffer[original_value_of_head+1] = item_from_thread1; buffer[original_value_of_head+2] = item_from_thread2; 

我们结束了

 buffer[original_value_of_head+1] = item_from_thread2; buffer[original_value_of_head+2] = whatever_was_there_previously; 

你可能会在客户端用这种蹩脚的编码离开,只有很less的线程,但在服务器端,这只能被认为是一个定时炸弹。 请使用同步结构,例如lock s或mutex es。

而且,只是为了完整性,行

 while( tail > head ); 

在方法pop_back()应该是

 while( tail >= head ); 

除非你想能够popup一个多于你实际推入的元素(甚至在推入任何东西之前popup一个元素)。

对不起,写了一个基本归结为一个长长的咆哮,但如果这只保留一个人复制和粘贴该淫秽的代码,这是值得的。

更新:以为我不妨给一个例子,像while(x>y); 其实是非常有意义的。 其实你曾经在“古老的”时代经常看到这样的代码。 咳嗽 DOS。 虽然在线程中使用过。 主要是作为一个后备的情况下注册一个中断挂钩是不可能的(你的孩子可能会把它翻译为“不可能注册一个事件处理程序”)。

 startAsynchronousDeviceOperation(..); 

这可能几乎是任何东西,例如告诉硬盘通过DMA读取数据,或告诉声卡通过DMAlogging,甚至可能调用不同处理器(如GPU)上的function。 通常通过类似outb(2)

 while(byteswritten==0); // or while (status!=DONE); 

如果与设备的唯一通信通道是共享内存,那就这样吧。 不过,期望看到现在的设备驱动程序和微控制器以外的代码。 显然,假定规格说明了内存位置是写入的最后一个位置。

volatile关键字旨在防止某些优化。 在这种情况下,如果没有关键字,编译器可能会将while循环展开成具体的指令序列,这些指令显然会破坏现实,因为这些值可能会在外部进行修改。

想象一下:

 int i = 2; while (i-- > 0) printf("%d", i); 

大多数编译器都会看这个,只是简单地生成两个printf调用 – 添加volatile关键字会导致产生CPU指令,调用计数器设置为2,并在每次迭代后检查值。

例如,

 volatile int i = 2; this_function_runs_on_another_process_and_modifies_the_value(&i); while(i-- > 0) printf("%d", i);