variable software qualifier language c++ while-loop volatile

c++ - software - Mientras bucle con el cuerpo vacío comprobando los volátiles, ¿qué significa esto?



volatile qualifier in c (4)

Como y se han declarado como volátiles, el programador espera que se modifiquen desde fuera del programa.

En ese caso, tu código permanecerá en el bucle

while(x>y);

y devolverá el valor xy después de que los valores se cambien desde afuera de modo que x <= y . La razón exacta de por qué se escribe esto puede adivinarse después de que nos cuente más sobre su código y dónde lo vio. El ciclo while en este caso es una técnica de espera para que se produzca algún otro evento.

Estoy mirando una clase de C ++ que tiene las siguientes líneas:

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

x y y son variables miembro de tipo volatile int . No entiendo esta construcción.

Encontré el código aquí: https://gist.github.com/r-lyeh/cc50bbed16759a99a226 . Supongo que no está garantizado que sea correcto o que funcione.


Otras respuestas ya han señalado en detalle lo que hace la instrucción, pero solo para recapitular eso, ya que y (o head en el ejemplo vinculado) se declara como cambios volatile hechos a esa variable de un hilo diferente causará que el ciclo while termine una vez la condición se ha cumplido.

Sin embargo, aunque el ejemplo de código vinculado es muy corto, es un ejemplo casi perfecto de cómo NO escribir código.

En primer lugar, la línea

while( tail > head );

perderá enormes cantidades de ciclos de CPU, bloqueando prácticamente un núcleo hasta que se cumpla la condición.

El código mejora aún más a medida que avanzamos.

buffer[head++ % N] = item;

Gracias a JAB por señalar que confundí aquí el post-pre-incremento. Corregido las implicaciones. Como no hay lock o mutex es, obviamente tendremos que asumir lo peor. El hilo se cambiará después de asignar el valor en el item y antes de que head++ ejecute. Murphy llamará nuevamente a la función que contiene esta declaración, asignando el valor del item en la misma posición de la head . Después de eso la head incrementa. Ahora volvemos al primer hilo e incrementamos el head nuevamente. Entonces, en lugar de

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

terminamos con

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

Usted podría salirse con la codificación descuidada de este modo en el lado del cliente con pocos hilos, pero en el lado del servidor esto solo podría considerarse una bomba de tiempo. Utilice construcciones de sincronización como lock s o mutex es en su lugar.

Y bueno, solo por el bien de la integridad, la línea

while( tail > head );

en el método pop_back() debería ser

while( tail >= head );

a menos que desee poder mostrar un elemento más de lo que realmente insertó (o incluso hacer estallar un elemento antes de insertar cualquier cosa).

Perdón por escribir lo que básicamente se reduce a una larga diatriba, pero si esto evita que una sola persona copie y pegue ese código obsceno, valió la pena.

Actualización: Pensé que también podría dar un ejemplo donde un código como while(x>y); en realidad tiene perfecto sentido. En realidad, solías ver códigos así con bastante frecuencia en los "viejos tiempos". tos DOS. Sin embargo, no se usó en el contexto del enhebrado. Principalmente como una alternativa en caso de que no fuera posible registrar un gancho de interrupción (los niños pueden traducir eso como "no es posible registrar un controlador de eventos").

startAsynchronousDeviceOperation(..);

Eso podría ser prácticamente cualquier cosa, por ejemplo, decirle al disco duro que lea datos a través de DMA, o decirle a la tarjeta de sonido que grabe a través de DMA, posiblemente incluso invoque funciones en un procesador diferente (como la GPU). Normalmente se inicia a través de algo como outb(2) .

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

Si el único canal de comunicación con un dispositivo es la memoria compartida, entonces que así sea. Sin embargo, no esperaba ver códigos como estos hoy en día fuera de los controladores de dispositivos y microcontroladores. Obviamente, asume que las especificaciones indican que la ubicación de la memoria es la última en la que se escribió.


Parece

while( x > y );

es un bucle giratorio . No se detendrá hasta que x <= y . Como y son volatile , pueden cambiarse fuera de esta rutina. Entonces, una vez que x <= y convierte en verdad, se devolverá x - y . Esta técnica se usa para esperar algún evento.

Actualizar

De acuerdo con la esencia que usted agregó, parece que la idea era implementar un búfer circular libre de bloqueo de subprocesos. Sí, la implementación es incorrecta. Por ejemplo, el fragmento de código original es

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

Incluso si la tail vuelve menos o igual a la head , no se garantiza que la head - tail devuelva un número positivo. El planificador puede cambiar la ejecución a otro subproceso inmediatamente después del ciclo while, y ese subproceso puede cambiar el valor de head . De todos modos, hay muchos otros problemas relacionados con la lectura y la escritura en el trabajo de memoria compartida (reordenamiento de memoria, etc.), así que simplemente ignore este código.


La palabra clave volatile está diseñada para evitar ciertas optimizaciones. En este caso, sin la palabra clave, el compilador podría desenrollar su ciclo while en una secuencia concreta de instrucciones que obviamente romperán en realidad ya que los valores podrían modificarse externamente.

Imagina lo siguiente:

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

La mayoría de los compiladores analizarán esto y simplemente generarán dos llamadas a printf : agregar la palabra clave volatile dará como resultado que genere las instrucciones de la CPU que invocan un contador establecido en 2 y una verificación del valor después de cada iteración.

Por ejemplo,

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