虽然循环与空体检查易失性int - 这是什么意思?

时间:2015-11-11 05:59:38

标签: c++ while-loop volatile

我正在查看一个C ++类,其中包含以下几行:

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

xyvolatile int类型的成员变量。我不明白这个结构。

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

4 个答案:

答案 0 :(得分:62)

由于xy已被声明为volatile,程序员希望它们将从程序外部更改。

在这种情况下,您的代码将保留在循环中

 while(x>y);

并在从外部更改值x-y后返回值x <= y。在您告诉我们有关您的代码的更多信息以及您看到它的位置之后,可以猜到写这个的确切原因。在这种情况下,while循环是一种等待其他事件发生的技术。

答案 1 :(得分:25)

似乎

while( x > y );

spinning loop。直到x <= y才会停止。由于xyvolatile,因此可以在此例程之外进行更改。因此,一旦x <= y变为真,将返回x - y。这种技术用于等待一些事件。

<强>更新

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

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

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

答案 2 :(得分:20)

其他回复已经详细指出了该指令的作用,但回顾一下,因为y(或链接示例中的head)被声明为volatile所做的更改来自不同线程的该变量将导致while循环在满足条件后完成。

然而,尽管linked code example非常短,但这是一个近乎完美的例子,说明 NOT 如何编写代码。

首先是

while( tail > head );

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

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

buffer[head++ % N] = item;

感谢JAB指出我错误的帖子 - 这里有预增量。纠正了影响。 由于没有lock s或mutex es,我们显然必须假设最坏的情况。在itemhead++执行之前分配值后,线程将切换。然后,Murphy将再次调用包含此语句的函数,并在同一item位置指定head的值。 之后head递增。现在我们切换回第一个线程并再次递增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;

你可能会在客户端使用很少的线程来躲避像这样的草率编码,但在服务器端,这只能被认为是定时炸弹。请改用同步构造,例如lockmutex es。

而且,仅仅为了完整性,行

while( tail > head );
方法pop_back()中的

应为

while( tail >= head );

除非您希望能够再弹出一个元素而不是实际推入(或者甚至在推入任何内容之前弹出一个元素)。

对于写一些基本归结为长期咆哮的对不起,但是如果这只能让一个人复制并粘贴那些淫秽的代码那么值得。

更新:我想我也可以举一个像while(x>y);这样的代码实际上非常有意义的例子。  实际上你过去经常在“好日子”里看到这样的代码。 咳嗽 DOS。 虽然没有在线程的上下文中使用。主要是作为一个后备,以防注册中断挂钩是不可能的(你的孩子可能会将其翻译为“无法注册事件处理程序”)。

startAsynchronousDeviceOperation(..);

这几乎可能是什么,例如告诉硬盘通过DMA读取数据,或告诉声卡通过DMA录制,甚至可能调用不同处理器(如GPU)上的功能。通常通过类似outb(2)

的方式启动
while(byteswritten==0); // or while (status!=DONE);

如果与设备的唯一通信通道是共享内存,那么就这样吧。不希望现在看到类似于设备驱动程序和微控制器之外的代码。显然假设规范声明内存位置是写入的最后一个。

答案 3 :(得分:7)

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

想象一下:

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

大多数编译器会查看这个并简单地生成对printf的两次调用 - 添加volatile关键字将导致它生成调用计数器设置为2的CPU指令并检查每次迭代后的值。

例如,

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