Предварительное распределение памяти с C ++ в среде реального времени - PullRequest
7 голосов
/ 12 мая 2010

У меня есть функция, которая получает входной буфер размером n байт и нуждается в вспомогательном буфере размером n байт для обработки данного входного буфера.

(я знаю, что vector выделяет память во время выполнения, скажем, я использую вектор, который использует статическую предварительно выделенную память. Представьте, что это НЕ вектор STL.)

Обычный подход

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

Поскольку я работаю в режиме реального времени, я хочу заранее выделить всю память, которая мне когда-либо понадобится, заранее.

Буфер выделяется только один раз при запуске. Я хочу, чтобы всякий раз, когда я выделял вектор, я автоматически выделял вспомогательный буфер для своей функции processData.

Я могу сделать что-то подобное с функцией шаблона

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

Однако много работать с шаблонами не очень весело (теперь давайте перекомпилируем все, так как я изменил комментарий!), И это заставляет меня вести бухгалтерию, когда я использую эту функцию.

Есть ли более приятные решения этой проблемы?

Ответы [ 8 ]

3 голосов
/ 12 мая 2010

Я не понимаю, как вы можете получить именно то, что вы описываете. Нечто подобное может быть хорошим компромиссом для вас.

void processData(vector<T>& vec)
{
    static vector<T> aux(vec.size());
    if (vec.size() > aux.size()) {
       aux.resize(vec.size());
    }
    ...
}
1 голос
/ 14 мая 2010

Вам нужно беспокоиться не о vector, а о распределителе памяти.

Вы могли бы идеально создать распределитель памяти, который предварительно выделяет ее память и затем передает ее в вектор при построении, для этого и нужен параметр шаблона Alloc!

И чтобы убедиться, что память не «виртуально» распределена, коснитесь ее при выделении.

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

Теперь вам просто нужно реализовать собственный распределитель, который ссылается на этот пул памяти, и передать его в векторную реализацию:)

1 голос
/ 12 мая 2010

скажем, я использую вектор который использует статическую предварительно выделенную память

Тогда вы сможете получить размер (или максимальный размер) предварительно выделенной памяти во время компиляции. Если бы такой вектор имел размер в качестве аргумента шаблона, работа с функцией processData была бы проще.

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 голос
/ 12 мая 2010

Я думаю, что вы можете предварительно выделить и mlock () достаточно большой пул памяти при запуске, а затем использовать обычные контейнеры STL с распределителями пула памяти ( Boost из FSBA или ваш самостоятельно).

Я искал это для нашего программного обеспечения реального времени, но тесты показали, что распределение памяти на нашем оборудовании достаточно быстрое для наших целей.

1 голос
/ 12 мая 2010

Даже если вам удастся это сделать, оно может не достичь того, чего вы хотите. В зависимости от того, какую операционную систему вы используете и как она реализует виртуальную память, вы можете обнаружить, что вы получаете lazy allocation, где только часть вашего выделения памяти фактически выделена и сопоставлена ​​изначально, а последующие страницы отображаются позже в результате страницы разломы. Если ваша ОС имеет mlock или эквивалент, тогда вы можете обойти это.

1 голос
/ 12 мая 2010

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

Это новое в STL? Или собственное расширение?

Типичным решением будет использование специального распределителя. Однако это не обязательно «более красиво» в коде.

Некоторые вводные слайды (предупреждение: powerpoint!)
Википедия
Google

0 голосов
/ 12 мая 2010

Возможно, вы можете переопределить новые и удалить операторы, но чем вам придется управлять вся ваша память самостоятельно. В начале вы можете выделить столько памяти, сколько хотите:

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 ();
0 голосов
/ 12 мая 2010

Не могли бы вы создать небольшую структуру, которая содержала бы ваш вектор и буфер одинакового размера? Тогда ваш вектор будет нести свой буфер обработки вместе с ним, куда бы он ни шел. Если вы передадите его по ссылке или по указателю, вам следует избегать копирования. Псевдокод следует ниже:

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

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

Любая функция, которая в данный момент принимает ваш векторный аргумент, будет принимать Container.

...