SystemC/TLM (C++) разделяет пул памяти; статические члены, статические методы, Singleton или?

Контекст: я пишу специальный протокол связи, который будет использоваться между моделями TLM (блоки HW описаны с помощью SystemC и, следовательно, C++). Понятие TLM не важно, просто обратите внимание, что это взаимодействие имитируется путем выделения объектов, общих полезных нагрузок (gps), которые передаются между этими моделями C++ блоков HW.

Цель: вместе с протоколом я хочу предоставить диспетчер памяти, который должен эффективно обрабатывать gps; это очень важно, так как в одной симуляции множество gps создается , используется и уничтожается, и это может сильно замедлить процесс. Моя цель также состоит в том, чтобы создать что-то простое, что могло бы использоваться другими без усилий.

Вопросы:

  1. Первая проблема, с которой я столкнулся, заключалась в создании единого общего пула для всех блоков, взаимодействующих с этим протоколом. Я думал о создании статического члена в классе mm, но потом понял, что:

    • Статические члены требуют определения в cpp. Это делает класс mm менее интуитивным в использовании (если это используют разные люди, некоторые забудут об этом), и я бы предпочел этого избежать.
    • В зависимости от того, где (и в каком?) В файле cpp выполняется определение статической переменной, в пуле могут отсутствовать параметры, необходимые для инициализации (т. Е. Количество созданных экземпляров в мм).
  2. Второй выпуск похож на первый. Я хочу подсчитать количество экземпляров и, таким образом, вместо пула мне нужно создать общий счетчик, который затем будет использоваться пулом для инициализации. Опять же, я хотел избежать определения статических переменных в файле 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 Если элемент управления вводит объявление одновременно, когда переменная инициализируется, параллельное выполнение должно ожидать завершения инициализации.

Заранее спасибо.

0 ответов

Другие вопросы по тегам