2011-11-18 2 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; 

} 

Ho ottenuto il codice da un tutorial sulla memoria condivisa. Ha funzionato fino a quando non ho definito struct LOCK e ho provato a scrivere LOCKs anziché char * nella memoria condivisa.Un semplice programma di memoria condivisa C++ scritto su linux: errore di segmentazione

Qualcuno potrebbe aiutarmi a capire il problema qui che causa l'errore di segmentazione?

+1

Imparare a compilare con tutte le avvertenze abilitati e debug di informazioni (vale a dire 'g ++ -Wall -g'). Quindi, usa il debugger 'gdb' per scoprire dove si trova l'errore SEGV. –

+0

se l'uso di stringhe e strutture vettoriali nella memoria condivisa è necessario, il modo migliore è utilizzare gli array statici nella struttura LOCK. – totten

risposta

10

si sta ponendo vector s e string s nella memoria condivisa. Entrambe le classi allocano memoria propria, che sarà allocata nello spazio di indirizzamento di qualsiasi processo genera l'allocazione e produrrà un segfault quando si accede dall'altra procedura. Si potrebbe provare a specificare gli allocatori per utilizzare quella memoria condivisa, ma poiché in C++ 03 si presume che gli allocatori siano stateless non sono sicuro che sia possibile.

considerazione il check-out come Boost.Interprocess fa.

+1

Anche se allocasse nella memoria condivisa, non funzionerebbe ancora. Le classi tracciano internamente i riferimenti assoluti alla memoria che allocano. Se i segmenti di memoria condivisa si mappano su un indirizzo diverso, i puntatori non puntano dove dovrebbero. Devi anche usare i puntatori relativi (relativi alla base del segmento di memoria condivisa). –

+0

@DavidSchwartz, il sistema operativo non lo nasconde ai programmi dello spazio utente? –

+2

@ TamásSzelei No. Come potrebbe? Se si esegue il mapping della memoria condivisa all'indirizzo X, il puntatore a un oggetto al suo interno sarà X + A (dove A è l'offset relativo). Se un altro processo mappa quella memoria condivisa all'indirizzo Y (perché X era in uso in quel processo, o solo per sfortuna), ha bisogno di un puntatore a Y + A per accedere agli stessi dati. Non puoi semplicemente passare il puntatore assoluto (X + A) da un processo a un altro o metterlo nella memoria condivisa. Devi passare il puntatore relativo (A) e ogni processo deve aggiungere il suo indirizzo di mappatura di base al puntatore prima di dereferenziarlo. –

1

Hai un numero di problemi. L'ovvio è che tu non costruisci il tuo oggetto . Nella forma opaca, che si sta facendo:

class Foo; 

Foo * p = get_memory(); 

p->bar = 5; // ouch! 

Cosa si dovrebbe fare, per lo meno:

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

(. Basta sostituire Foo da LOCK per la vostra situazione)

Tuttavia , diventa più complicato: vector e string richiedono allocazioni dinamiche. Quella memoria deve vivere nello stesso spazio indirizzo del tuo LOCK. Quindi il modo standard per risolvere questo è quello di scrivere il proprio allocatore e passare che:

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; 
}; 

Infine, è necessario scrivere una classe allocatore conforme che mette memoria nello stesso spazio di indirizzamento come quello in cui il vostro LOCK oggetto Alla fine andrà:

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

typedef Lock<shared_allocator> LOCK; 
+0

Come è stato sottolineato ai commenti nella mia risposta, un allocatore personalizzato non è sufficiente. I puntatori relativi sono necessari per indicare il posto giusto in ogni spazio di indirizzamento del processo. –

+0

@ K-ballo: l'allocatore dovrebbe occuparsi di ciò, non? I nuovi allocatori di stato dovrebbero rendere la vita molto più semplice, poiché ora possono memorizzare un indirizzo di base. –

+0

Non proprio sicuro. Forse se l'allocatore ha un tipo di puntatore senza puntatori ... –

0

So che è molto tempo fa. Ma stavo cercando how-to (ricordare) su mem condivisa e questa discussione è interessante.

miei due centesimi al demander:

  • perche non che la lettura e la scrittura di SharedMemory è esattamente come la lettura e la scrittura in un filesystem.
  • ID memoria condivisa == file_handle da aperto (...);

    Quindi ... Come si fa a CORRETTAMENTE serializzare e quindi std lettura-scrittura :: string o anche std :: vector in un file? Realmente espandi/riduci un file std :: string o std :: all'interno di un FILE ??

Grazie :)