impulsar la eliminación de managed_shared_memory cuando el proceso está adjunto

Tengo 2 procesos, el proceso 1 crea un segmento managed_shared_memory boost y el proceso 2 abre este segmento. El proceso 1 se reinicia y el inicio del proceso 1 tiene lo siguiente:

struct vshm_remove { vshm_remove() { boost::interprocess::shared_memory_object::remove("VMySharedMemory"); } ~vshm_remove() { boost::interprocess::shared_memory_object::remove("VMySharedMemory"); } } vremover; 

Entiendo que cuando se inicie o finalice el proceso 1, el método de eliminación se activará en mi memoria compartida, pero ¿no debería eliminarlo solo si el Proceso 2 no está conectado a ella? Estoy adjuntando a la memoria compartida en el proceso 2 usando lo siguiente,

 boost::interprocess::managed_shared_memory *vfsegment; vfsegment = new boost::interprocess::managed_shared_memory(boost::interprocess::open_only, "VMySharedMemory"); 

Me doy cuenta de que la memoria compartida se elimina independientemente del proceso 2 que se conecte.

No creo que haya ninguna mención en la documentación de que shared_memory_object::remove fallará si se adjunta un proceso.

Por favor, consulte esta sección para referencia: Eliminar la memoria compartida . Particularmente:

Esta función puede fallar si los objetos de la memoria compartida no existen o se abre mediante otro proceso.

Esto significa que una llamada a shared_memory_object::remove("foo") intentará eliminar la memoria compartida llamada “foo” sin importar qué.

La implementación de esa función ( fuente aquí ) refleja ese comportamiento:

 inline bool shared_memory_object::remove(const char *filename) { try{ //Make sure a temporary path is created for shared memory std::string shmfile; ipcdetail::tmp_filename(filename, shmfile); return ipcdetail::delete_file(shmfile.c_str()); } catch(...){ return false; } } 

En mi experiencia con el código de producción publicado, tuve éxito al no llamar a shared_memory_object::remove hasta que ya no necesito acceder a la memoria compartida.

Escribí un progtwig principal de ejemplo muy simple que podría encontrar útil. Se adjuntará, creará o eliminará la memoria compartida según cómo lo ejecute. Después de comstackr, prueba los siguientes pasos:

  1. Ejecute con c para crear la memoria compartida (1.0K de forma predeterminada) e inserte datos ficticios
  2. Ejecute con o para abrir (“adjuntar a”) la memoria compartida y leer datos ficticios (la lectura se realizará en un bucle cada 10 segundos de forma predeterminada)
  3. En una sesión separada, ejecute con r para eliminar la memoria compartida
  4. Corra de nuevo con o para intentar abrir. Observe que esto (casi con seguridad) fallará porque la memoria compartida fue (de nuevo, casi con seguridad) eliminada durante el paso anterior
  5. Siéntete libre de matar el proceso desde el segundo paso.

En cuanto a por qué el paso 2 anterior sigue siendo capaz de acceder a los datos después de una llamada a shared_memory_object::remove , consulte Construcción de la memoria compartida administrada . Específicamente:

Cuando abrimos una memoria compartida gestionada.

  • Se abre un objeto de memoria compartida.
  • Todo el objeto de memoria compartida se asigna en el espacio de direcciones del proceso.

Probablemente, debido a que el objeto de memoria compartida se asigna al espacio de direcciones del proceso, el archivo de memoria compartida ya no se necesita directamente.

Me doy cuenta de que este es un ejemplo bastante artificial, pero pensé que algo más concreto podría ser útil.

 #include  // tolower() #include  #include  #include  // sleep() #include  #include  int main(int argc, char *argv[]) { using std::cerr; using std::cout; using std::endl; using namespace boost::interprocess; if (argc == 1) { cout << "usage: " << argv[0] << " \n 'c' create\n 'r' remove\n 'a' attach" << endl; return 0; } const char * shm_name = "shared_memory_segment"; const char * data_name = "the_answer_to_everything"; switch (tolower(argv[1][0])) { case 'c': if (shared_memory_object::remove(shm_name)) { cout << "removed: " << shm_name << endl; } managed_shared_memory(create_only, shm_name, 1024).construct(data_name)(42); cout << "created: " << shm_name << "\nadded int \"" << data_name << "\": " << 42 << endl; break; case 'r': cout << (shared_memory_object::remove(shm_name) ? "removed: " : "failed to remove: " ) << shm_name << endl; break; case 'a': { managed_shared_memory segment(open_only, shm_name); while (true) { std::pair data = segment.find( data_name ); if (!data.first || data.second == 0) { cerr << "Allocation " << data_name << " either not found or empty" << endl; break; } cout << "opened: " << shm_name << " (" << segment.get_segment_manager()->get_size() << " bytes)\nretrieved int \"" << data_name << "\": " << *data.first << endl; sleep(10); } } break; default: cerr << "unknown command" << endl; break; } return 0; } 

Una cosa interesante adicional – agregue un caso más:

 case 'w': { managed_shared_memory segment(open_only, shm_name); std::pair data = segment.find( data_name ); if (!data.first || data.second == 0) { cerr << "Allocation " << data_name << " either not found or empty" << endl; break; } *data.first = 17; cout << "opened: " << shm_name << " (" << segment.get_segment_manager()->get_size() << " bytes)\nretrieved int \"" << data_name << "\": " << *data.first << endl; } break; 

La opción adicional 'w' hace que la memoria se adjunte y escriba '17' en su lugar ("el número aleatorio más aleatorio"). Con esto puedes hacer lo siguiente:

Consola 1: Do 'c', luego 'a'. Reporta la memoria creada con valor 42.

Consola 2: Do 'w'. En Console1 verás que el número ha cambiado.

Consola 2: Do 'r'. La memoria se ha eliminado correctamente, la Consola 1 todavía imprime 17.

Consola 2: Do 'c'. Informará la memoria como creada con el valor 42.

Consola 2: hacer 'a'. Verás 42, la consola 1 todavía imprime 17.

Esto confirma, siempre que funcione de la misma manera en todas las plataformas, pero boost declara que sí lo hace, que puede usar esta forma para enviar bloques de memoria de un proceso a otro, mientras que el "productor" solo necesita confirmación de que el "consumidor "adjunté el bloque para que" productor "ahora pueda eliminarlo. El consumidor tampoco tiene que separar el bloque anterior antes de adjuntar el siguiente.