Quiero implementar un counter sin bloqueo, un int de 4 bytes, en la memoria compartida de System V. El escritor es un programa C++, el lector es un programa Python. Trabajando más o menos así:
counter de actualizaciones de código C++ en una operación atómicacounter y tiene una vista consistente de la memoria (la coherencia eventual es perfectamente aceptable)Dentro del lenguaje C++ hay operaciones atómicas de obtención/actualización que permiten esto y garantizan la consistencia de la memoria, creo que lo mismo es cierto en Python.
Sin embargo, según tengo entendido, las suposiciones en C++ con respecto a las operaciones atómicas no se aplican necesariamente al código escrito y compilado en otro lenguaje y compilador.
¿Hay alguna manera de lograr una vista consistente de la memoria compartida en todos los idiomas que no implique implementar bloqueos de bajo nivel?
Sí, usando la biblioteca atomics , junto con una biblioteca de memoria compartida adecuada (por ejemplo, mmap o shared_memory ).
Este ejemplo asume que su int atómico está en los primeros 4 bytes del segmento de memoria compartida.
from atomics import atomicview, MemoryOrder, INT from multiprocessing import shared_memory # connect to existing shared memory segment shmem = SharedMemory(name="test_shmem") # get buf corresponding to "atomic" region buf = shmem.buf[:4] # atomically read from buffer with atomicview(buffer=buf, atype=INT) as a: value = a.load(order=MemoryOrder.ACQUIRE) # print our value print(value) # del our buf object (or shmem.close() will complain) del buf # close our shared memory handle shmem.close() Podemos usar el orden de memoria ACQUIRE aquí en lugar del SEQ_CST predeterminado.
La atomicview solo se puede crear y usar con una declaración with , por lo que deberá mantener su buf manualmente (y administrar su vida útil correctamente).
Nota: soy el autor de esta biblioteca.
¿Hay alguna manera de lograr una vista consistente de la memoria compartida en todos los idiomas que no implique implementar bloqueos de bajo nivel?
No, no en general.
Primero, diría que esto no tiene nada que ver con los lenguajes, sino con las plataformas, la arquitectura, la implementación o el sistema operativo reales.
Debido a que los idiomas difieren bastante, tome Python por ejemplo: no tiene una forma nativa de idioma de acceder a la memoria directamente o, digamos, de una manera de bajo nivel. Sin embargo, algunas de sus implementaciones ofrecen su propia API. Los lenguajes destinados a un uso de tan bajo nivel tienen abstracciones para eso, como C, C++ o Rust. Pero esas abstracciones se implementan a menudo de manera bastante diferente, ya que a menudo dependen de dónde se ejecuta, interpreta o compila el código. Un número entero para algunas arquitecturas es big endian, en la mayoría, como x86 o arm, es little endian. Los sistemas operativos también tienen algo que decir, ya que, por ejemplo, se usa y abstrae la memoria.
Y aunque muchos lenguajes tienen abstracciones comunes de la memoria lineal, se complica aún más con la atómica: el compilador para C++ podría generar código de máquina, es decir, un ensamblaje que verifique si la ejecución de la CPU admite nuevas instrucciones atómicas enteras sofisticadas y usarlas o recurrir a ellas. a menudo admitía banderas atómicas más el número entero. Solo podría depender del sistema operativo, un bloqueo de giro o API estandarizadas definidas por POSIX, SystemV, Linux, Windows si el código tiene el lujo de ejecutarse en un entorno administrado por el sistema operativo.
Para idiomas no imperativos, se vuelve aún más complicado.
Entonces, para intercambiar datos entre idiomas, las implementaciones de esos idiomas deben usar algún intercambio común. Podrían intentar hacerlo directamente a través de la memoria compartida, por ejemplo. Esto entonces se llama Interfaz Binaria de Aplicación (ABI), ya que una abstracción de memoria es al menos común para ellos a priori. O el sistema operativo o la arquitectura podrían incluso estandarizar tales cosas o incluso admitir API.
System V sería una API diseñada para dicho intercambio, pero dado que AFAIK no tiene una abstracción para abstracciones atómicas o sin bloqueo, la respuesta sigue siendo no, incluso con el contexto de System V fuera del título.
Voy a estar en desacuerdo con algunas de las afirmaciones de Superlokkus.
La primitiva mmap está disponible tanto en C++ como en Python. Esa primitiva te da memoria que está en una página física compartida por ambos procesos. Diferentes direcciones virtuales, misma página física de memoria. Los cambios realizados por un proceso son inmediatamente visibles por el otro proceso. Así es como tiene que funcionar. Opera a nivel de hardware. Las abstracciones son irrelevantes.
Ahora, eso NO significa que pueda recibir una notificación de esos cambios. Si está sondeando en un bucle (presumiblemente un bucle amistoso con dormir entre comprobaciones), verá el cambio la próxima vez que compruebe.