Es C++11 atomic utilizable con mmap?


Quiero agregar el control de red de un puñado de parámetros utilizados por un servicio (demonio) que se ejecuta en un sistema embebido Linux. No hay necesidad de llamadas de procedimiento, cada parámetro se puede sondear de una manera muy natural. La memoria compartida parece una buena manera de mantener el código de red fuera del demonio, y limitar el acceso compartido a un conjunto de variables cuidadosamente controladas.

Dado que 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 de C++11 y no con múltiples procesos (potencialmente, ni siquiera con subprocesos del sistema operativo). Específicamente, si la implementación utiliza cualquier estructura de datos almacenada fuera del bloque de memoria compartida, en un escenario multiproceso esto fallaría.

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

La integral atómica las especializaciones y la especialización atomic<bool> tendrán un diseño estándar. Cada uno tendrá un constructor por defecto trivial y un destructor trivial. Cada uno de ellos soportará sintaxis de inicialización agregada.

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

Valor predeterminado trivial la construcción y destrucción me parece excluir los datos asociados por objeto, ya sea almacenados dentro del objeto, a través de una variable miembro puntero o a través de una asignación externa.

Sin embargo, no veo nada que excluya a una implementación de usar una única sección global mutex / crítica (o incluso una colección global, siempre y cuando los elementos de la colección no estén asociados con objetos atómicos individuales something algo en las líneas de un esquema de asociación de caché podría usarse para reducir false conflicto). Obviamente, el acceso desde múltiples procesos fallaría en una implementación usando un mutex global, porque los usuarios tendrían mutexes independientes y no se sincronizarían entre sí.

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


Acabo de notar que la construcción por defecto trivial deja el objeto en un estado no listo, y una llamada a atomic_init es requerir. Y el Estándar menciona la inicialización de bloqueos. Si estos se almacenan dentro del objeto (y la asignación de memoria dinámica parece imposible, ya que el destructor sigue siendo trivial), entonces se compartirían entre los procesos. Pero sigo 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.

Author: Ben Voigt, 2013-08-19

2 answers

Llego dos meses tarde, pero estoy teniendo exactamente el mismo problema en este momento y creo que he encontrado algún tipo de respuesta. La versión corta es que debería funcionar, pero no estoy seguro de si dependería de ella.

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 cualquier cosa relacionada con el multiprocesamiento no es estándar.

  • Sin embargo, la sección 29.4 "Propiedad sin bloqueo" del estándar (o al menos el draft I have, N3337) termina con esta nota:

    [Nota: Las operaciones que están libres de bloqueo también deben estar libres de direcciones. Es decir, operaciones atómicas en el mismo la ubicación de la memoria a través de dos direcciones diferentes se comunicará atómicamente. La aplicación no debe depende de cualquier estado por proceso. Esta restricción permite la comunicación por memoria que se asigna a un procesar más de una vez y por 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 estén 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 aplicación no dependerá de ningún estado por proceso. Si bien tal definición está más allá del alcance de la estándar, una declaración clara de nuestra intención permitirá una expresión portátil de la clase de los programas ya existentes.

    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 o no estar libres de bloqueo para type en particular, dependiendo de las capacidades de la plataforma. Y podemos comprobar cualquier variable x llamando x.is_lock_free().

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

 20
Author: phaker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-12 18:41:27

Hasta C++11, el estándar no especificaba cómo comparten memoria varios subprocesos, por lo que escribimos programas con múltiples subprocesos que dependían del comportamiento específico de la implementación. El estándar todavía no especifica cómo interactúan los procesos con memoria compartida, o si lo prefiere, los subprocesos que solo comparten memoria parcialmente. Sea lo que sea que termines haciendo, confiarás en garantías específicas de implementación.

Dicho esto, creo que una implementación que soporte la memoria compartida de procesos intentará haga que sus mecanismos de sincronización de subprocesos como atomics se puedan usar en la memoria compartida de procesos para la sincronización de procesos. Por lo menos, creo que sería difícil idear una implementación sin bloqueos de una especialización std::atomic que no funcione correctamente en el proceso cruzado.

 1
Author: Casey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-19 20:23:54