并发对象池给予提升::shared_ptr

发布于 2024-11-15 10:55:42 字数 2169 浏览 3 评论 0原文

我想实现一个并发对象池,其中返回shared_ptr,并且不需要将其显式返回到池。我基本上在并发队列中为其分配了一个推送共享指针的数组,并实现了一个自定义删除器。似乎有效。我错过了什么吗?

#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

I wanted to implement a concurrent object pool where in a shared_ptr is returned and explicitly returning it to the pool is not required. I basically allocated an array pushed shared_ptrs for it in a concurrent queue and implemented a custom deletor. Seems to work. Am I missing anything?

#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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

顾挽 2024-11-22 10:55:42

ConcurrentObjectPool 的析构函数中设置 _goingDown 标志与在 payBack() 中读取该标志之间存在竞争。它可能会导致内存泄漏。

实际上,如果您不尝试使析构函数安全地与 payBack() 并发运行,也许会更好。无论如何,这是不安全的,因为 _goingDown 标志是池对象的一部分,因此在池被销毁后访问它会导致未定义的行为 - 即所有对象都必须返回到池中在它被摧毁之前。

There is a race between setting the _goingDown flag in the destructor of ConcurrentObjectPool and reading the flag in payBack(). It can lead to memory leaks.

Actually, maybe it's better if you do not try to make the destructor safe to run concurrently with payBack(). It's not safe anyway, starting from the fact that the _goingDown flag is a part of the pool object and so accessing it after the pool is destroyed would cause undefined behavior - i.e. all objects must be returned to the pool before it is destroyed.

乞讨 2024-11-22 10:55:42

看起来不错。您使用它时遇到任何问题吗?

Looks good. Are you experiencing any problems using it?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文