una sirven salida que programación programacion parametros parametro para los función funcion estructura entrada ejemplos argumentos argumento c++ c++11 atomic memory-model

c++ - sirven - parametros y argumentos java



¿Por qué se da memory_order como un argumento en tiempo de ejecución a las funciones std:: atomic (3)

std::atomic funciones std::atomic tales como store y load toman un argumento std::memory_order . El argumento se puede determinar en tiempo de ejecución, como cualquier otro argumento de función. Sin embargo, el valor real puede afectar la optimización del código durante la compilación. Considera lo siguiente:

std::atomic<int> ai1, ai2; int value = whatever; void foo() { std::memory_order memOrd = getMemoryOrder(); register int v = value; // load value from memory ai1.store(v, memOrd); // dependency on v''s value ai2.store(1, memOrd); // no dependency. could this be move up? }

Si memOrd pasa a ser memory_order_relaxed , la segunda tienda podría moverse con seguridad frente a la primera. Esto agregará un poco de trabajo extra entre el value carga y su uso, lo que podría evitar los bloqueos requeridos. Sin embargo, si memOrd es memory_order_seq_cst , no debe permitirse el cambio de tiendas, ya que algún otro subproceso puede contar con que ai1 ya esté establecido en value si ai2 se establece en 1.

Lo que me pregunto es por qué se definió el orden de la memoria como un argumento de tiempo de ejecución en lugar de tiempo de compilación. ¿Hay alguna razón para que alguien examine el entorno en el tiempo de ejecución antes de decidir la mejor semántica de operaciones de memoria?


Es solo una especificación de interfaz que permite que el memory_order se especifique en tiempo de ejecución. No requiere la implementación para usar esa asignación.

Por ejemplo, en el hardware x86 memory_order_seq_cst es probablemente lo que obtienes, lo que especifiques. memory_order_relaxed simplemente no está disponible debido al protocolo de coherencia de caché de hardware.

En otro hardware, donde puede optimizar el orden conocido de tiempo de compilación, la implementación puede ofrecer sobrecargas adicionales que aprovechan los parámetros predeterminados.


La razón por la que esto se implementa como un parámetro de tiempo de ejecución en lugar de un parámetro de tiempo de compilación es para permitir la composición.

Supongamos que está escribiendo una función que utiliza las operaciones atómicas proporcionadas para realizar el equivalente de una operación de carga , pero operando en una construcción de nivel superior. Al tener el orden de memoria especificado como un parámetro de tiempo de ejecución, la carga de nivel superior puede pasar un parámetro de orden de memoria suministrado por el usuario a la operación atómica de bajo nivel que se requiere para proporcionar el pedido sin que la operación de nivel superior tenga que ser una plantilla.

Normalmente, las instrucciones atómicas estarán en línea, y el compilador eliminará la prueba del parámetro de orden de memoria en el caso de que en realidad sea una constante de tiempo de compilación.


Los escritores de C ++ podrían haber implementado memory_order como una característica de tiempo de compilación, en lugar de una característica de tiempo de ejecución. Sin embargo, no habrían ganado nada por ello. Cualquier compilador capaz de comprender los pedidos de memoria optimizará fácilmente los casos obvios como x.load (memory_order_acq), por lo que no se beneficiarían de ser una característica de tiempo de compilación.

Mientras tanto, el uso de una función de tiempo de ejecución significa que no tenían que introducir ninguna nueva notación para las órdenes de memoria. Sólo son argumentos de función. Esto significa que obtuvieron los mismos beneficios que la versión en tiempo de compilación, con menos complejidad.

Mientras tanto, es muy conveniente para compiladores más simples, ya que pueden implementar atomic como una clase normal, sin tener que tratarlo especialmente.

T atomic<T>::compare_exchange_strong(T& compare, T exchange, memory_order order) { lockBeforeUsing(order); // handle the acquire part of the memory order if (mValue == compare) { compare = mValue; mValue = compare; } else { compare = mValue; } lockAfterUsing(order); // handle the release part of the memory order }