2011-11-18 51 views
6
#include <stdio.h> 
#include <sys/shm.h> 
#include <sys/stat.h> 
#include <string> 
#include <vector> 
#include <iostream> 

using namespace std; 

struct LOCK { 
    string name; 
    string type; 
    vector <string> pids; 
}; 

int main() 

{ 

    int segment_id; 

    LOCK* shared_memory; 

    struct shmid_ds shmbuffer; 

    int segment_size; 

    const int shared_segment_size = 0x6400; 



    /* Allocate a shared memory segment. */ 

    segment_id = shmget (IPC_PRIVATE, shared_segment_size, 

        IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR); 

    /* Attach the shared memory segment. */ 

    shared_memory = (LOCK*) shmat (segment_id, 0, 0); 

    printf ("shared memory attached at address %p\n", shared_memory); 

    /* Determine the segment's size. */ 

    shmctl (segment_id, IPC_STAT, &shmbuffer); 

    segment_size =    shmbuffer.shm_segsz; 

    printf ("segment size: %d\n", segment_size); 

    /* Write a string to the shared memory segment. */ 

    //sprintf (shared_memory, "Hello, world."); 
    shared_memory -> name = "task 1"; 
    shared_memory -> type = "read"; 
    (shared_memory -> pids).push_back("12345"); 
    (shared_memory -> pids).push_back("67890"); 

    /* Detach the shared memory segment. */ 

    shmdt (shared_memory); 



    /* Reattach the shared memory segment, at a different address. */ 

    shared_memory = (LOCK*) shmat (segment_id, (void*) 0x5000000, 0); 

    printf ("shared memory reattached at address %p\n", shared_memory); 

    /* Print out the string from shared memory. */ 

    //printf ("%s\n", shared_memory -> name); 
    cout << "Name of the shared memory: " + shared_memory -> name << endl; 

    /* Detach the shared memory segment. */ 

    shmdt (shared_memory); 



    /* Deallocate the shared memory segment. */ 

    shmctl (segment_id, IPC_RMID, 0); 



    return 0; 

} 

Recibí el código de un tutorial sobre memoria compartida. Funcionó hasta que definí struct LOCK y traté de escribir LOCKs en lugar de char * en la memoria compartida.Un simple programa de memoria compartida en C++ escrito en Linux: falla de segmentación

¿Podría alguien ayudarme a resolver el problema aquí que causa la falla de segmentación?

+1

Aprende a compilar con todas las advertencias habilitados y la depuración de la información (es decir, 'g ++ -Wall -g'). Luego, use su depurador 'gdb' para averiguar dónde está la falla SEGV. –

+0

si es necesario utilizar cadenas y estructuras similares a vectores en la memoria compartida, la mejor manera es usar matrices estáticas en la estructura LOCK. – totten

Respuesta

10

Usted está colocando vector sy string s en la memoria compartida. Ambas clases asignan memoria propia, que se asignará dentro del espacio de direcciones de cualquier proceso que genere la asignación, y producirá una segfault cuando se acceda desde el otro proceso. Podría intentar especificar asignadores para usar esa memoria compartida, pero como en C++ 03 se supone que las asignaciones son sin estado, no estoy seguro de si será posible.

Considere comprobar cómo lo hace Boost.Interprocess.

+1

Incluso si se asignó en la memoria compartida, todavía no funcionaría. Las clases siguen internamente los punteros absolutos a la memoria que asignan. Si los segmentos de memoria compartida se asignan a una dirección diferente, los punteros no apuntarán donde deberían. También debe usar punteros relativos (relativos a la base del segmento de memoria compartida). –

+0

@DavidSchwartz, ¿el sistema operativo no lo oculta en los programas de espacio de usuario? –

+2

@ TamásSzelei No. ¿Cómo podría ser? Si mapea la memoria compartida en la dirección X, su puntero a un objeto en ella será X + A (donde A es el desplazamiento relativo). Si otro proceso mapea esa memoria compartida en la dirección Y (porque X estaba en uso en ese proceso, o simplemente por mala suerte), necesita un puntero a Y + A para acceder a los mismos datos. No puede simplemente pasar el puntero absoluto (X + A) de un proceso a otro o ponerlo en la memoria compartida. Debe pasar el puntero relativo (A) y cada proceso debe agregar su dirección de mapeo base al puntero antes de desreferenciarlo. –

1

Tiene una serie de problemas. El más obvio es que usted no construye su objeto. En forma opaca, que está haciendo actualmente:

class Foo; 

Foo * p = get_memory(); 

p->bar = 5; // ouch! 

Lo que debería hacer, por lo menos:

void * addr = get_memory(sizeof(Foo)); 
Foo * p = ::new (addr) Foo; 
// do work 
p->~Foo(); // done 

(. Basta con sustituir Foo por LOCK para su situación)

Sin embargo , se vuelve más complicado: vector y string requieren asignaciones dinámicas. Esa memoria debe vivir en el mismo espacio de direcciones que su LOCK. Así que la forma estándar de resolver esto es para escribir su propio asignador y pasar que:

template <template <typename> class Alloc> 
struct Lock 
{ 
    typedef std::basic_string<char, std::char_traits<char>, Alloc<char>> shared_string; 

    shared_string name; 
    shared_string type; 

    std::vector<shared_string, Alloc<shared_string>> pids; 
}; 

Por último, usted tiene que escribir una clase asignador conforme que pone la memoria en el mismo espacio de direcciones como aquel en el que el objeto LOCK finalmente irá:

template <typename T> 
class shared_allocator { /* write this! */ } 

typedef Lock<shared_allocator> LOCK; 
+0

Como se señaló en los comentarios en mi respuesta, un asignador personalizado no es suficiente. Se necesitan punteros relativos para señalar el lugar correcto en cada espacio de direcciones de proceso. –

+0

@ K-ballo: se espera que el asignador se encargue de eso, ¿no? Los nuevos asignadores con estado deberían facilitar la vida, ya que ahora pueden almacenar una dirección base. –

+0

No estoy seguro. Tal vez, si el asignador tiene un tipo de puntero no puntero ... –

0

Sé que es hace mucho tiempo. Pero estaba buscando cómo hacerlo (recordar) sobre la memoria compartida y este hilo es interesante.

mi granito de arena a la demandante:

  • tenga en cuenta que la lectura y la escritura en SharedMemory es exactamente igual que la lectura y la escritura en un sistema de archivos.
  • ID de memoria compartida == file_handle desde abierto (...);

    Entonces ... ¿Cómo serializar CORRECTAMENTE y luego leer-escribir std :: string o incluso std :: vector en un ARCHIVO? ¿Realmente 'expandes/contraes' un std :: string o std :: vector desde un ARCHIVO?

Gracias :)

Cuestiones relacionadas