Search code examples
c#c++lockingtype-constraints

Implementing lock in C++


Sorry that the question of this problem might be a bit vague. I'm trying to port this ObjectPool code from C# into C++ but seems there are some parts where I don't know how I should proceed. Codes are as follows:

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;
            }
        }
    }
}

My questions are:

1) How should I implement that constraint on generic parameter T in C++? (class, new())

2) Is there a simple way to implement the mutex lock part?

3) Will it be more efficient to define _pool as vector instead of T[] in C++?

edit -> Implemented something as:

#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);
}

Wondering if there's any problem with this code...


Solution

  • Here's a naive snippet that illustrates one possible approach:

    #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;
      }
    };
    

    This example assumes that m_data points to infinite memory. Reallocation is a bit tricky and involves making lots of copies.

    A simpler approach would be to wrap your synchronized structure around another, existing standard container such as std::vector<T>.