2010-05-12 7 views
7

Tengo una función que obtiene un búfer de entrada de n bytes, y necesita un búfer auxiliar de n bytes para procesar el búfer de entrada proporcionado.Memoria de preasignación con C++ en entorno de tiempo real

(sé vector es la asignación de memoria en tiempo de ejecución, digamos que estoy usando un vector que utiliza memoria preasignada estática. Imagínese esto es NO un vector de STL.)

El enfoque habitual es

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

Dado que estoy trabajando en un entorno de tiempo real, deseo preasignar toda la memoria que necesitaré de antemano.

El búfer se asigna solo una vez al inicio. Quiero que cada vez que asigne un vector, automáticamente asigne el buffer auxiliar para mi función processData.

puedo hacer algo similar con una función de plantilla

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

Sin embargo trabajando mucho con las plantillas no es muy divertido (ahora vamos a recompilar todo lo que ya he cambiado un comentario!), Y me obliga a hacer un poco de contabilidad cada vez que uso esta función.

¿Hay diseños más agradables alrededor de este problema?

+1

pregunta obligatoria: ¿ha perfilado su código para demostrar que la dinámica asignaciones de memoria realmente son un problema? Sé que todo el mundo dice que debe asignar todo por adelantado para cosas en tiempo real, pero realmente depende de su sistema. –

+2

Según los requisitos, lo que hice en el pasado es asignar dinámicamente un tamaño predeterminado. Luego compare el tamaño requerido con el tamaño ya asignado y simplemente reasigne si no hay suficiente espacio. esto asegurará que siempre tenga suficiente espacio y que las asignaciones eventualmente se detengan, estabilizando el sistema. –

+0

@Kristo: "en tiempo real" significa que es un error si el procesamiento lleva más tiempo que un tiempo especificado. La creación de perfiles solo puede mostrar el peor caso que ocurrió durante la ejecución de un perfil, no el peor caso teórico. La asignación dinámica solo es segura si el asignador puede garantizar un límite superior en el tiempo que tomará. –

Respuesta

3

No veo cómo puede obtener exactamente lo que describe. Algo como esto podría ser un buen compromiso para ti.

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

tenga en cuenta que esto mueve la reserva de memoria desde el inicio a la primera llamada, lo que podría ser un problema.Además, las dos versiones generalmente no son seguras para hilos (no estoy seguro si esto es una preocupación para el OP) – peterchen

+0

Es por eso que mencioné que no fue exactamente lo que se pidió. Un punto a favor de esta solución: no tiene un vector estático por tamaño posible, lo que podría ser un desperdicio. – AProgrammer

0

¿Podría crear una estructura pequeña que contuviera su vector y un búfer del mismo tamaño? Entonces harías que tu vector llevara su búfer de procesamiento junto con él donde quiera que vaya. Si lo pasa por referencia o puntero, debe evitar la sobrecarga de la copia. Pseudocódigo sigue a continuación:

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

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

Cualquier función que actualmente lleva su vector argumento sería luego tomar un Container.

1

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

es que los nuevos en STL? O una extensión personalizada?

La solución típica sería usar un asignador personalizado. Sin embargo, esto no es necesariamente "más bonito" en el código.

Some intro slides (advertencia: PowerPoint)
Wikipedia
Google

+0

Citando a mí mismo: "(Sé que el vector está asignando memoria en tiempo de ejecución, digamos que estoy usando un vector que usa memoria preasignada estática. Imagine que NO es un vector STL)". –

1

Incluso si usted tiene éxito en hacer esto, no puede lograr lo que quiere. Dependiendo del sistema operativo que esté utilizando y cómo implemente la memoria virtual, puede encontrar que obtiene lazy allocation, donde solo se asigna y asigna inicialmente una parte de la asignación de memoria, y posteriormente se mapean más páginas como resultado de fallas de página. Si su sistema operativo tiene mlock o equivalente, entonces puede evitar esto.

+0

¿Fallas de página? En el sistema de misión crítica en tiempo real? Yo creo que no. ¿Dónde almacenaríamos las páginas de memoria si no tenemos disco? Todo el código debe caber en la memoria y permanecer allí. ¿O me estoy perdiendo algo? –

+0

@Elazar: no dijiste qué sistema operativo estabas usando, así que solo podía asumir que estás usando un sistema operativo "común o de jardín" como Linux. Si está utilizando algo como VxWorks (o al menos un sistema operativo sin VM), entonces es una historia diferente, por supuesto. –

+0

es vainilla Linux el "jardín común" de los sistemas en tiempo real? Creo que VxWorks merece este título más que Linux. –

1

Creo que podría preasignar y mlock() un grupo de memoria suficientemente grande en el inicio y luego usar contenedores STL regulares con asignadores de grupo de memoria (Boost de FSBA o el suyo).

Estaba investigando eso para nuestro software en tiempo real, pero las pruebas mostraron que la asignación de memoria es lo suficientemente rápida en nuestro hardware para nuestros propósitos.

0

Probablemente puede anular los operadores nuevos y eliminar, pero tendrá que administrar toda su memoria por su cuenta. Se pueden asignar más memoria que desea al principio:

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

digamos que estoy usando un vector que utiliza la memoria preasignada estática

Entonces usted debe ser capaz de obtener tamaño (o tamaño máximo) de la memoria preasignada en tiempo de compilación. Si dicho vector tiene su tamaño como argumento de plantilla, entonces trabajar con la función processData sería más fácil.

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

No es el vector necesita preocuparse, que es el asignador de memoria.

Puede crear perfectamente un asignador de memoria que preasigne su memoria y luego la pase al vector cuando la construya, ¡para eso sirve el parámetro de plantilla Alloc!

Y para asegurarse de que la memoria no está "virtualmente" asignada, tóquela cuando la asigne.

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

Ahora, "sólo" tienen que poner en práctica un asignador de costumbre que se refiere a este bloque de memoria y pasarlo a la puesta en práctica del vector :)

+0

¿cómo sabría el asignador personalizado cuántas veces lo llamaré? –

+0

Personalizado significa que usted mismo lo programa, puede hacer lo que quiera en cuanto a su funcionalidad, como por ejemplo registrar las asignaciones y desasignaciones para futuros perfiles, etc. –

Cuestiones relacionadas