Как сказано в комментариях, не получайте поточно-ориентированный распределитель памяти, выделяйте память для каждого потока.
Как вы подразумевали в своем обновлении, вам необходимо эффективно управлять свободным / используемым. Это довольно простая проблема, учитывая постоянный тип и отсутствие параллелизма.
Например (с головы не проверено):
template<typename T>
class ThreadStorage
{
std::vector<T> m_objs;
std::vector<size_t> m_avail;
public:
explicit ThreadStorage(size_t count) : m_objs(count, T()) {
m_avail.reserve(count);
for (size_t i = 0; i < count; ++i) m_avail.push_back(i);
}
T* alloc() {
T* retval = &m_objs[0] + m_avail.back();
m_avail.pop_back();
return retval;
}
void free(T* p) {
*p = T(); // Assuming this is enough destruction.
m_avail.push_back(p - &m_objs[0]);
}
};
Затем для каждого потока создайте экземпляр ThreadStorage и при необходимости вызовите alloc () и free ().
Вы можете добавить умные указатели для управления вызовами free () для вас и оптимизировать вызовы конструктора / деструктора, если это дорого.
Вы также можете посмотреть на boost :: pool.
Обновление:
Новое требование для отслеживания вещей, которые были использованы, чтобы их можно было обработать за второй проход, мне кажется немного неясным. Я думаю, что вы имеете в виду, что, когда первичная обработка завершена на объекте, вам нужно не освобождать его, а сохранять ссылку на него для обработки второго этапа. Некоторые объекты вы просто будете возвращены в пул и не будете использоваться для обработки второго этапа.
Полагаю, вы хотите сделать это в той же теме.
В качестве первого прохода вы можете добавить метод, подобный этому, в ThreadStorage и вызывать его, когда хотите выполнить обработку всех невыпущенных экземпляров T. Никакого дополнительного учета не требуется.
void do_processing(boost::function<void (T* p)> const& f) {
std::sort(m_avail.begin(), m_avail.end());
size_t o = 0;
for (size_t i = 0; i != m_avail.size(); ++i) {
if (o < m_avail[i]) {
do {
f(&m_objs[o]);
} while (++o < m_avail[i]);
++o;
} else of (o == m_avail[i])
++o;
}
for (; o < m_objs.size(); ++o) f(&m_objs[o]);
}
Предполагается, что ни один другой поток не использует экземпляр ThreadStorage, что разумно, поскольку он является локальным по потоку. Опять же, на макушке моей головы, не проверено.