SystemC/TLM (C++) разделяет пул памяти; статические члены, статические методы, Singleton или?
Контекст: я пишу специальный протокол связи, который будет использоваться между моделями TLM (блоки HW описаны с помощью SystemC и, следовательно, C++). Понятие TLM не важно, просто обратите внимание, что это взаимодействие имитируется путем выделения объектов, общих полезных нагрузок (gps), которые передаются между этими моделями C++ блоков HW.
Цель: вместе с протоколом я хочу предоставить диспетчер памяти, который должен эффективно обрабатывать gps; это очень важно, так как в одной симуляции множество gps создается , используется и уничтожается, и это может сильно замедлить процесс. Моя цель также состоит в том, чтобы создать что-то простое, что могло бы использоваться другими без усилий.
Вопросы:
Первая проблема, с которой я столкнулся, заключалась в создании единого общего пула для всех блоков, взаимодействующих с этим протоколом. Я думал о создании статического члена в классе mm, но потом понял, что:
- Статические члены требуют определения в cpp. Это делает класс mm менее интуитивным в использовании (если это используют разные люди, некоторые забудут об этом), и я бы предпочел этого избежать.
- В зависимости от того, где (и в каком?) В файле cpp выполняется определение статической переменной, в пуле могут отсутствовать параметры, необходимые для инициализации (т. Е. Количество созданных экземпляров в мм).
Второй выпуск похож на первый. Я хочу подсчитать количество экземпляров и, таким образом, вместо пула мне нужно создать общий счетчик, который затем будет использоваться пулом для инициализации. Опять же, я хотел избежать определения статических переменных в файле cpp и гарантировать порядок инициализации.
Я учел в основном:
- статические члены (отбрасываются по вышеуказанным причинам)
- Синглтоны (отброшены, потому что мне не нужно создавать целый класс для пула, чтобы сделать его видимым для других и для одного экземпляра)
- статические методы (подходы, которые я наконец выбрал, и это недалеко от полного синглтона)
Это код, который я создал (только соответствующая часть):
/**
* Helper class to count another class' number of instances.
*/
class counter {
public:
// Constructor
counter() : count(0) {}
//Destructor
virtual ~counter() {}
private:
unsigned int count;
public:
unsigned int get_count() {return count;}
void incr_count() {count++;}
void decr_count() {count--;}
};
template <unsigned int MAX = 1>
class mm: public tlm::tlm_mm_interface {
//////////////////////////////TYPEDEFS AND ENUMS/////////////////////////////
public:
typedef tlm::tlm_generic_payload gp_t;
///////////////////////////CLASS (CON/DE)STRUCTOR////////////////////////////
public:
// Constructor
mm() {inst_count().incr_count();}
// Copy constructor
mm(const mm&) {inst_count().incr_count();}
// Destructor
virtual ~mm() {} // no need to decrease instance count in our case
////////////////////////////////CLASS METHODS////////////////////////////////
public:
// Counter for number of isntances.
static counter& inst_count() {
static counter cnt;
return cnt;
}
/* This pattern makes sure that:
-- 1. The pool is created only when the first alloc appears
-- 2. All instances of mm have been already created (known instance sequence)
-- 3. Only one pool exists */
static boost::object_pool<gp_t>& get_pool() {
static boost::object_pool<gp_t> p(
mm<MAX>::inst_count().get_count() * MAX / 2, // creation size
mm<MAX>::inst_count().get_count() * MAX // max size used
);
return p;
}
// Allocate
virtual gp_t* allocate() {
//...
return gp;
}
// Free the generic payload and data_ptr
virtual void free(gp_t* gp) {
//...
get_pool().destroy(gp);
}
}
Теперь заголовок класса блока инициатора должен иметь член:
mm m_mm;
И класс блока инициатора cpp должен использовать это так:
tlm_generic_payload* gp;
gp = m_mm.allocate();
//...
m_mm.free(gp); // In truth this is called by gp->release()...
// ...not important here
Имея опыт работы в электронном виде, я в основном пытаюсь улучшить стиль кодирования, изучить новые подходы и оптимизировать скорость / распределение памяти.
Есть ли лучший способ добиться этого? В частности, учитывая мои сомнения:
- Мне кажется, не оптимальным обходным решением является инкапсуляция счетчика в классе, его локальное (но статическое) размещение в статическом методе, а затем то же самое для пула.
- хотя SystemC "ядро моделирования" является однопоточным, мне нужно рассмотреть многопоточный случай... Я не уверен, что отношения между этими двумя статическими методами безопасны, даже если вы независимо от них должны быть безопасны... с C++03 g++ добавляет код для гарантии этого и с C++ 11:
§6.7 [stmt.dcl] p4 Если элемент управления вводит объявление одновременно, когда переменная инициализируется, параллельное выполнение должно ожидать завершения инициализации.
Заранее спасибо.