teorico programas programación programacion practico paso para ingenieros ejemplos dev comandos basicos c++ multithreading c++11 shared-memory atomic

programas - programacion en c++ para ingenieros pdf



¿Se puede usar C++ 11 atómico<T> con mmap? (2)

Quiero agregar el control de red de unos pocos parámetros utilizados por un servicio (daemon) que se ejecuta en un sistema Linux incorporado. No hay necesidad de llamadas de procedimiento, cada parámetro puede ser encuestado de una manera muy natural. La memoria compartida parece una buena forma de mantener el código de red fuera del demonio y limitar el acceso compartido a un conjunto de variables cuidadosamente controlado.

Como no quiero que las escrituras parciales causen visibilidad de valores nunca escritos, estaba pensando en usar std::atomic<bool> y std::atomic<int> . Sin embargo, me preocupa que std::atomic<T> pueda implementarse de una manera que solo funcione con subprocesos C ++ 11 y no con múltiples procesos (potencialmente, ni siquiera con subprocesos del sistema operativo). Específicamente, si la implementación utiliza alguna estructura de datos almacenada fuera del bloque de memoria compartida, en un escenario de múltiples procesos, esto fallaría.

Veo algunos requisitos que sugieren que std::atomic no mantendrá un objeto de bloqueo incrustado o un puntero a datos adicionales:

Las especializaciones atómicas integrales y la especialización atomic<bool> deberán tener un diseño estándar. Cada uno tendrá un constructor predeterminado trivial y un destructor trivial. Deberán soportar cada uno la sintaxis de inicialización agregada.

Deberá haber puntero especializaciones parciales de la plantilla de clase atómica. Estas especializaciones tendrán un diseño estándar, constructores por defecto triviales y destructores triviales. Deberán soportar cada uno la sintaxis de inicialización agregada.

La construcción y destrucción por defecto trivial me parece que excluye los datos asociados por objeto, ya sea que estén almacenados dentro del objeto, a través de una variable miembro de puntero, o a través de una asignación externa.

Sin embargo, no veo nada que excluya a una implementación del uso de una sola sección de exclusión / crítica global (o incluso una colección global, siempre que los elementos de la colección no estén asociados con objetos atómicos individuales, algo parecido a un esquema de asociación de caché) podría ser utilizado para reducir los conflictos falsos). Obviamente, el acceso desde múltiples procesos fallaría en una implementación usando un mutex global, porque los usuarios tendrían mutex independientes y no se sincronizarían entre sí.

¿Se permite que una implementación de atomic<T> haga cosas que son incompatibles con la memoria compartida entre procesos, o hay otras reglas que la hacen segura?

Acabo de atomic_init cuenta de que la construcción predeterminada trivial deja el objeto en un estado no listo, y se requiere una llamada a atomic_init . Y el estándar menciona la inicialización de las cerraduras. Si estos se almacenan dentro del objeto (y la asignación de memoria dinámica parece imposible, ya que el destructor sigue siendo trivial), se compartirían entre procesos. Pero todavía estoy preocupado por la posibilidad de un mutex global.

En cualquier caso, garantizar una sola llamada a atomic_init para cada variable en una región compartida parece difícil ... así que supongo que tendré que alejarme de los tipos atómicos de C ++ 11.


Hasta C ++ 11, el estándar no especificaba cómo varios subprocesos comparten memoria, por lo que escribimos programas con varios subprocesos que se basaban en el comportamiento específico de la implementación. El estándar aún no especifica cómo interactúan los procesos con memoria compartida, o si lo prefiere, hilos que solo comparten parcialmente la memoria. Independientemente de lo que termine haciendo, dependerá de las garantías específicas de la implementación.

Dicho esto, creo que una implementación que admita la memoria compartida de proceso intentará hacer que sus mecanismos de sincronización de subprocesos, como los atómicos, puedan utilizarse en la memoria compartida de proceso para la sincronización de procesos. Por lo menos, creo que sería difícil idear una implementación sin bloqueo de una especialización std :: atomic que no funcione correctamente entre procesos.


Tengo dos meses de retraso, pero ahora mismo tengo exactamente el mismo problema y creo que he encontrado algún tipo de respuesta. La versión corta es que debería funcionar, pero no estoy seguro si dependería de ello.

Esto es lo que encontré:

  • El estándar C ++ 11 define un nuevo modelo de memoria, pero no tiene noción de "proceso" a nivel del sistema operativo, por lo que todo lo relacionado con el multiprocesamiento no es estándar.

  • Sin embargo, la sección 29.4 "Propiedad sin bloqueo" de la norma (o al menos el borrador que tengo, N3337) termina con esta nota:

    [Nota: Las operaciones que están libres de bloqueo también deben estar libres de dirección. Es decir, las operaciones atómicas en la misma ubicación de memoria a través de dos direcciones diferentes se comunicarán atómicamente. La implementación no debe depender de ningún estado por proceso. Esta restricción permite la comunicación por memoria que se asigna a un proceso más de una vez y por la memoria que se comparte entre dos procesos. - nota final]

    Esto suena muy prometedor. :)

  • Esa nota parece provenir de N2427 , que es aún más explícita:

    Para facilitar la comunicación entre procesos a través de la memoria compartida, nuestra intención es que las operaciones sin bloqueo también sean libres de direcciones. Es decir, las operaciones atómicas en la misma ubicación de memoria a través de dos direcciones diferentes se comunicarán atómicamente. La implementación no dependerá de ningún estado por proceso. Si bien tal definición está más allá del alcance del estándar, una declaración clara de nuestra intención permitirá una expresión portátil de la clase de un programa que ya existe.

    Así que parece que sí, se supone que todas las operaciones sin bloqueo funcionan en este escenario exacto.

  • Ahora, las operaciones en std::atomic<type> son atómicas, pero pueden estar o no bloqueadas para un type particular, dependiendo de las capacidades de la plataforma. Y podemos verificar cualquier variable x llamando a x.is_lock_free() .

  • Entonces, ¿por qué escribí que no dependería de esto? No puedo encontrar ningún tipo de documentación para gcc, llvm o cualquier otra persona que sea explícita al respecto.