Параллельный объектный пул, дающий импульс :: shared_ptr - PullRequest
1 голос
/ 14 июня 2011

Я хотел реализовать пул параллельных объектов, в котором возвращается значение shared_ptr, и явное возвращение его в пул не требуется. Я в основном выделил для него массив push_redrs в параллельной очереди и реализовал пользовательский обработчик. Кажется, работает. Я что-то упустил?

#ifndef CONCURRENTOBJECTPOOL_H
#define CONCURRENTOBJECTPOOL_H

#include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp>
#include <tbb/concurrent_queue.h>

namespace COP
{

template<typename T>
class ConcurrentObjectPool;

namespace 
{
template<typename T>
class ConcurrentObjectPoolDeletor
{
public:
  ConcurrentObjectPoolDeletor(ConcurrentObjectPool<T>& aConcurrentObjectPool): 
  _concurrentObjectPool(aConcurrentObjectPool) {}

  void operator()(T *p) const;

private:
  ConcurrentObjectPool<T>& _concurrentObjectPool;  
};
} // Anonymous namespace for ConcurrentObjectPoolDeletor

template <typename T>
class ConcurrentObjectPool
{
 public:
 ConcurrentObjectPool(const unsigned int aPoolSize)
   : _goingDown(false),
     _poolSize(aPoolSize), 
     _pool(new T[_poolSize]),
     _ConcurrentObjectPoolDeletor(*this)
  {
    for(unsigned int i = 0; i < _poolSize; ++i)
      {
        boost::shared_ptr<T> curr(&_pool[i], _ConcurrentObjectPoolDeletor);
        _objectQueue.push(curr);
      }
  }

  boost::shared_ptr<T> loan()
  {
    boost::shared_ptr<T> curr;
    _objectQueue.pop(curr);
    return curr;
  }

  ~ConcurrentObjectPool()
  {
    _goingDown = true;
    _objectQueue.clear();
  }

 private:
  void payBack(T * p)
  {
    if (! _goingDown)
      {
        boost::shared_ptr<T> curr(p, _ConcurrentObjectPoolDeletor);
        _objectQueue.push(curr);
      }
  }

  bool _goingDown;
  const unsigned int _poolSize; 
  const boost::shared_array<T> _pool;
  const ConcurrentObjectPoolDeletor<T> _ConcurrentObjectPoolDeletor;
  tbb::concurrent_bounded_queue<boost::shared_ptr<T> > _objectQueue;
  friend class ConcurrentObjectPoolDeletor<T>;
};

namespace
{
template<typename T>
void ConcurrentObjectPoolDeletor<T>::operator()(T *p) const
{
  _concurrentObjectPool.payBack(p);
}
} // Anonymous namespace for ConcurrentObjectPoolDeletor

} // Namespace COP

#endif // CONCURRENTOBJECTPOOL_H

Ответы [ 2 ]

2 голосов
/ 15 июня 2011

Существует гонка между установкой флага _goingDown в деструкторе ConcurrentObjectPool и чтением флага в payBack().Это может привести к утечкам памяти.

На самом деле, может быть, будет лучше, если вы не попытаетесь сделать деструктор безопасным для одновременной работы с payBack().В любом случае это небезопасно, начиная с того факта, что флаг _goingDown является частью объекта пула, и поэтому доступ к нему после уничтожения пула может привести к неопределенному поведению - то есть все объекты должны быть возвращены в пул до его уничтожения.

0 голосов
/ 14 июня 2011

выглядит хорошо.Испытываете ли вы какие-либо проблемы с его использованием?

...