Search code examples
c#dictionarythread-safetyauto-incrementpool

Auto-increment dictionary key in c#


I'm trying to create specific object pool in c# . I have two basic methods, getObject and putObject and one thread-safe collection - concurrentDictionary (because of requiment to have some keys to identify objects in pool).

But when I remove and return object from dictionary, I need to reorganize this collection, and also when I want to put new object to collection, I want to auto-increment key. Is there any solution to achieve this ? Or any other collection, which can help me to achive same effect and which can help me to create object pool ? (I have two pools, one to create objects, but objects can contain data, so i have also some "data pool" and "data" should be object with some non-constant size , I need this solution for "data pool" ).

Or maybe, do you have some know-how, how to make object pool (memory pool) with objects than can contain different data with different size ?

some example code

->Foreach is there because I want to find the closest match of size of "data objects" and then, if there is any suitable object, I want to return it. If not, I create new.

namespace MPool
{
    public class DataPool<T>
    {
        private ConcurrentDictionary<int,T> _objects;
        private Func<T> _objectGenerator;

        public DataPool(Func<T> objectGenerator)
        {
            if (objectGenerator == null)
                throw new ArgumentNullException("Chyba metoda objectGenerator");
            _objects = new ConcurrentDictionary<int,T>();
            _objectGenerator = objectGenerator;
        }

        public T GetObject(int size)
        {
            int diverse = Int32.MaxValue;
            T item = default(T);
            int key = -1;
            foreach (KeyValuePair<int,T> obj in _objects) {
                if (GetObjectSize(obj.Value) == size) {
                    //item = obj.Value;
                    key = obj.Key;
                    break;
                } else {
                    if (Math.Abs((GetObjectSize(obj.Value) - size)) < diverse) {
                        diverse = Math.Abs((GetObjectSize(obj.Value) - size));
                        if (diverse < (2 * GetObjectSize(obj.Value))) {
                            //item = obj.Value;
                            key = obj.Key;
                        }
                    }
                }
            }
            if (key==-1) {
                return _objectGenerator();
            } else {
                _objects.TryRemove(key, out item);
                return item;
            }
        }

        public void PutObject(T item)
        {
            //_objects.AddOrUpdate
        }

        public void Free()
        {
            while (!_objects.IsEmpty) {
                _objects.Clear();
            }
        }

        private int GetObjectSize(T TestObject)
        {
            BinaryFormatter bf = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            byte[] Array;
            bf.Serialize(ms, TestObject);
            Array = ms.ToArray();
            return Array.Length;
        }
    }
}

Solution

  • I have a comment about the posted code that is not directly related to what you are trying to do (as I am still somewhat unsure as to what you want to do), but I feel like this should be addressed.

    You are computing the size of the object potentially 4 times in each loop iteration. Since you are adding these objects to your collection at one time, I would suggest you make a helper class within this class that can store the object and its size and you compute it at the time of creation and then store these objects in the collection.

    public DataPool<T>
    {
            internal class DataStructHelper<T>
            {
                public T DataObject { get; private set; }
                public int Size { get; private set; }
                public DataStructHelper(T dataObject)
                {
                    DataObject = dataObject;
                    Size = GetObjectSize(dataObject);
                }
    
                private int GetObjectSize(T TestObject)
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    using (MemoryStream ms = new MemoryStream())
                    {
                        byte[] Array;
                        bf.Serialize(ms, TestObject);
                        return ms.ToArray().Length;
                    }
                }
            }
        }
    // Other code here
    }
    

    Not knowing how your class is going to be used and how many threads you plan on hitting this thing with, etc. I would consider just using a regular list and locking around access. You can store the items in sorted order and use BinarySearch to insert and search for items based on the size (you will need to provide the compare function).