在C ++中实现锁定

时间:2011-11-17 20:34:29

标签: c# c++ locking type-constraints

很抱歉,这个问题的问题可能有点模糊。我正在尝试将这个ObjectPool代码从C#移植到C ++中,但似乎有些部分我不知道应该如何继续。代码如下:

using System;

namespace FastRank
{
    public class ObjectPool<T> where T : class, new()
    {
        private int _count;

        private T[] _pool;

        public ObjectPool(int initSize)
        {
            _pool = new T[initSize];
        }

        public T Get()
        {
            lock (_pool)
            {
                if (_count > 0)
                {
                    --_count;
                    T item = _pool[_count];
                    _pool[_count] = null;
                    return item;
                }
            }
            return new T();
        }

        public void Return(T item)
        {
            lock (_pool)
            {
                if (_count == _pool.Length)
                    Array.Resize(ref _pool, _pool.Length*2 + 1);
                _pool[_count++] = item;
            }
        }
    }
}

我的问题是:

1)我应该如何在C ++中对泛型参数T实现该约束? (class,new())

2)有没有一种简单的方法来实现互斥锁部分?

3)在C ++中将_pool定义为vector而不是T []会更有效吗?

编辑 - &gt;实现了以下内容:

#include "object_pool.h"

#include <boost/thread.hpp>
#include <vector>
using namespace std;

template <class T>
ObjectPool<T>::ObjectPool(int init_size) {
  pool_.reserve(init_size);
}

template <class T>
T ObjectPool<T>::Get() {
  boost::lock_guard<boost::mutex> lock(guard_);
  int sz = (int) pool_.size();
  if (sz == 0) {
    throw "Object pool size is now zero.";
  }
  else {
    T item = pool_[sz-1];
    pool_.pop_back();
    return item;
  } 
}

template <class T>
void ObjectPool<T>::Return(T item) {
  boost::lock_guard<boost::mutex> lock(guard_);
  pool_.push_back(item);
}

想知道这段代码是否有问题......

3 个答案:

答案 0 :(得分:2)

  

1)我应该如何在C ++中对泛型参数T实现该约束? (class,new())

一般来说,不要。如果它不能满足约束,它将无法编译。很简单。有一些棘手的方法来获得更好的错误信息,但我已经忘记了它们,因为我从来没有打扰过。

  

2)有没有一种简单的方法来实现互斥锁部分?

使用boost::mutex

  

3)在C ++中将_pool定义为vector而不是T []会更有效吗?

考虑到没有大小的本地T[],是的。使用std::vector。 (您可以将其作为参数,但不能在变量定义中使用。)

答案 1 :(得分:1)

这是一个天真的片段,说明了一种可能的方法:

#include <mutex>

template <typename T>
class SyncStack
{
   T         * m_data;
   std::size_t m_size;
   std::size_t m_count;
   std::mutex  m_lock;

public:
  T get()
  {
    std::lock_guard<std::mutex> lock(m_lock);

    if (m_count == 0) { throw UnderrunException; }

    --m_count;
    T x(m_data[m_count]);
    m_data[m_count].~T();

    return x;
  }

  void put(T x)
  {
    std::lock_guard<std::mutex> lock(m_lock);
    ::new (m_data + m_count) T(std::move(x));
    ++m_count;
  }
};

此示例假定m_data指向无限内存。重新分配有点棘手,涉及制作大量副本。

更简单的方法是将同步结构包装在另一个现有标准容器(如std::vector<T>)周围。

答案 2 :(得分:0)

这就是我实现它的方式。您可以将tbb::concurrenct_queue替换为std::mutex看守std::queue,但效率会降低。使用此实现,您需要担心将对象“返回”回池,它会自动处理。

#include <memory>
#include <tbb/concurrent_queue.h>

namespace FastRank
{
    template<typename T>
    class object_pool
    {
        typedef tbb::concurrent_bounded_queue<std::shared_ptr<T>> pool_t;       
        std::shared_ptr<pool_t> pool_;
    public:

        object_pool() : pool_(new pool_t())
        {
        }

        std::shared_ptr<T> get()
        {
            std::shared_ptr<T> ptr;
            if(!pool_.try_pop(ptr))
                ptr = std::make_shared<T>();

            auto pool = pool_;
            return std::shared_ptr<T>(ptr.get(), [pool, ptr](T*){pool->push(ptr);});
        }
    }
}

没有concurrent_queue

#include <memory>
#include <queue>
#include <boost/mutex.hpp>

namespace FastRank
{
    template<typename T>
    class object_pool
    {
        typedef std::pair<std::queue<std::shared_ptr<T>>, boost::mutex> pool_t;     
        std::shared_ptr<pool_t> pool_;
    public:

        object_pool() : pool_(new pool_t())
        {
        }

        std::shared_ptr<T> get()
        {
            std::shared_ptr<T> ptr;
            {
                boost::scoped_lock<boost::mutex> lock(pool_->second);
                if(!pool_->first.empty())
                {
                     ptr = std::move(pool->first.front());
                     pool->first.pop()
                }
            }

            if(!ptr)
                ptr = std::make_shared<T>();

            auto pool = pool_;
            return std::shared_ptr<T>(ptr.get(), [pool, ptr](T*)
            {
                boost::scoped_lock<boost::mutex> lock(pool->second);                    
                pool->push(ptr);
            });
        }
    }
}