2010-05-12 14 views
7

Ho una funzione che ottiene un buffer di input di n byte e richiede un buffer ausiliario di n byte per elaborare il buffer di input specificato.Preallocazione della memoria con C++ in ambiente realtime

(lo so vettore è l'allocazione della memoria in fase di esecuzione, diciamo che sto usando un vettore che utilizza una memoria preallocato statica. Immaginate questo NON è un vettore STL.)

L'approccio comune è

void processData(vector<T> &vec) { 
    vector<T> &aux = new vector<T>(vec.size()); //dynamically allocate memory 
    // process data 
} 
//usage: 
processData(v) 

Dal momento che sto lavorando in un ambiente in tempo reale, desidero preallocare tutta la memoria che avrò mai bisogno in anticipo.

Il buffer viene assegnato una sola volta all'avvio. Voglio che quando alloco un vettore, allocherò automaticamente il buffer ausiliario per la mia funzione processData.

che posso fare qualcosa di simile con una funzione template

static void _processData(vector<T> &vec,vector<T> &aux) { 
    // process data 
} 
template<size_t sz> 
void processData(vector<T> &vec) { 
    static aux_buffer[sz]; 
    vector aux(vec.size(),aux_buffer); // use aux_buffer for the vector 
    _processData(vec,aux); 
} 
// usage: 
processData<V_MAX_SIZE>(v); 

Tuttavia lavorando molto con i modelli non è molto divertente (ora diamo ricompilare tutto da quando ho cambiato un commento!), E mi costringe a fare un po 'di contabilità ogni volta che uso questa funzione.

Esistono progetti più interessanti in merito a questo problema?

+1

Campo obbligatorio: hai profilato il codice per dimostrare che la dinamica le allocazioni di memoria sono davvero un problema? So che tutti dicono che dovresti allocare tutto in anticipo per cose in tempo reale, ma in realtà dipende dal tuo sistema. –

+2

A seconda dei requisiti, ciò che ho fatto in passato è allocare dinamicamente una dimensione predeterminata. Quindi confrontare le dimensioni richieste con le dimensioni già allocate e riallocare se non c'è abbastanza spazio. questo assicurerà di avere sempre abbastanza spazio e che le allocazioni finiranno per stabilizzare il sistema. –

+0

@ Kristo: "tempo reale" indica che si tratta di un errore se l'elaborazione richiede più tempo di un intervallo di tempo specificato. Il profilo può mostrare solo il caso peggiore che si è verificato durante l'esecuzione di un profilo, non il caso peggiore teorico. L'allocazione dinamica è sicura solo se l'allocatore può garantire un limite superiore al tempo necessario. –

risposta

3

Non vedo come si possa ottenere esattamente ciò che si descrive. Qualcosa di simile potrebbe essere un buon compromesso per te.

void processData(vector<T>& vec) 
{ 
    static vector<T> aux(vec.size()); 
    if (vec.size() > aux.size()) { 
     aux.resize(vec.size()); 
    } 
    ... 
} 
+1

nota che questo sposta la prenotazione della memoria dall'avvio alla prima chiamata - che potrebbe già essere un problema.Inoltre, entrambe le versioni in genere non sono thread-safe (non sono sicuro che questa sia una preoccupazione per l'OP) – peterchen

+0

Ecco perché ho detto che non era esattamente quello che veniva chiesto. Un punto a favore di questa soluzione: non ha un vettore statico per dimensione possibile, che potrebbe essere uno spreco. – AProgrammer

0

È possibile creare una piccola struttura contenente il vettore e un buffer di dimensioni uguali? Allora avresti il ​​tuo vettore che trasporta il suo buffer di elaborazione con esso ovunque vada. Se lo passi per riferimento o puntatore, devi evitare il sovraccarico di copia. Pseudocodice segue qui sotto:

struct Container 
{ 
    vector<T> vec; 
    vector<T> buf; 

    Container(int size) 
    { 
     vec.reserve(size); 
     buf.reserve(size); 
    } 
}; 

Qualsiasi funzione che attualmente prende il vostro argomento vettore avrebbe poi prendere un Container.

1

vector aux(vec.size(),aux_buffer); // use aux_buffer for the vector

è che i nuovi in ​​STL? O un'estensione personalizzata?

La soluzione tipica sarebbe l'utilizzo di un allocatore personalizzato. Tuttavia, questo non è necessariamente "più carino" nel codice.

Some intro slides (Attenzione: powerpoint)
Wikipedia
Google

+0

Chiedo a me stesso: "(So che il vettore sta allocando memoria in fase di esecuzione, diciamo che sto usando un vettore che usa una memoria prealloca statica. Immagina che NON sia un vettore STL.)". –

1

Anche se si riesce a fare questo, non può ottenere quello che vuoi. A seconda del sistema operativo in uso e del modo in cui implementa la memoria virtuale, è possibile che si ottenga lazy allocation, in cui solo parte dell'allocazione di memoria viene effettivamente allocata e mappata inizialmente e altre pagine vengono mappate in seguito a causa di errori di pagina. Se il tuo sistema operativo ha mlock o equivalente, potresti riuscire a ovviare a questo problema.

+0

errori di pagina? In tempo reale sistema mission-critical? Penso di no. Dove dovremmo memorizzare le pagine di memoria se non abbiamo un disco? Tutto il codice dovrebbe adattarsi alla memoria e rimanere lì. O mi sta sfuggendo qualcosa? –

+0

@Elazar: non hai detto quale sistema operativo stai usando, quindi posso solo presumere che tu stia utilizzando un sistema operativo "comune o giardino" come Linux. Se stai usando qualcosa come VxWorks (o almeno un OS senza VM), allora è una storia diversa, naturalmente. –

+0

Linux vanilla è il "giardino comune" dei sistemi in tempo reale? Penso che VxWorks meriti questo titolo più di Linux. –

1

Penso che si potrebbe pre-allocare e mlock() un numero sufficientemente ampio pool di memoria all'avvio, e quindi utilizzare contenitori STL regolari con ripartitori pool di memoria (Boost del FSBA o il proprio).

L'ho cercato per il nostro software in tempo reale, ma i test hanno dimostrato che l'allocazione della memoria è abbastanza veloce sul nostro hardware per i nostri scopi.

0

Probabilmente è possibile ignorare gli operatori nuovi ed eliminare, ma di quello che si dovrà gestire tutta la memoria da soli. È possibile allocare la quantità di memoria che si desidera all'inizio:

void* operator new (std::size_t size) throw (std::bad_alloc); 
void* operator new[] (std::size_t size) throw (std::bad_alloc); 
void operator delete (void* ptr) throw(); 
void operator delete[] (void* ptr) throw(); 
1

diciamo che sto usando un vettore che utilizza la memoria preallocato statica

Poi si dovrebbe essere in grado di ottenere dimensione (o dimensione massima) della memoria preallocata in fase di compilazione. Se un vettore di questo tipo aveva le sue dimensioni come argomento modello, allora lavorare con la funzione processData sarebbe più semplice.

template<class T, size_t sz> 
class vector 
{ 
enum { size = sz } //either max size 
... 
} 

template<class Vector> 
static void _processData(Vector &vec,Vector &aux) 
{ 
    // process data 
} 
template<class Vector> 
void processData(Vector &vec) { 
    static aux_buffer[Vector::size]; 
    //no need to pass size into constructor, as Vector type knows it already 
    Vector aux(aux_buffer); // use aux_buffer for the vector 
    _processData(vec,aux); 
} 
// usage: 
vector<int, 30> v1; 
vector<float, 40> v2; 
//no need to specify template parameter explicitly 
//every call uses its own function instance and its own buffer of different size 
processData(v1); 
processData(v2); 
1

Non è la vector è necessario preoccuparsi, è l'allocatore di memoria.

Si può creare perfettamente un allocatore di memoria che prealloca la sua memoria e poi lo passa al vettore quando lo si genera, ecco a cosa serve il parametro del modello Alloc!

E per assicurarsi che la memoria non sia allocata "virtualmente", toccarla quando la si assegna.

scoped_array<byte> buffer = new byte[SIZE]; 
memset(buffer.get(), 0, SIZE); 

Ora, è "solo" sono tenuti ad attuare un allocatore personalizzato, che si riferisce a questo pool di memoria e passarlo alla realizzazione vettore :)

+0

in che modo l'allocatore personalizzato sa quante volte lo chiamerò? –

+0

Personalizzato significa che lo si programma da soli, quindi si può fare tutto ciò che si desidera per la sua funzionalità, come ad esempio registrare le allocazioni e le deallocazioni per la profilatura futura ecc ... –