Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PushGP/HeuristicLab.PushGP/HeuristicLab.Problems.ProgramSynthesis/Push/Data/Pool/ObjectPool.cs @ 14727

Last change on this file since 14727 was 14727, checked in by pkimmesw, 7 years ago

#2665 PushGP HL Integration, Views, Parameters

File size: 3.8 KB
Line 
1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5using System;
6
7namespace HeuristicLab.Problems.ProgramSynthesis.Push.Data.Pool {
8  using System.Threading;
9
10  /// <summary>
11  /// Generic implementation of object pooling pattern with predefined pool size limit. The main
12  /// purpose is that limited number of frequently used objects can be kept in the pool for
13  /// further recycling.
14  ///
15  /// Notes:
16  /// 1) it is not the goal to keep all returned objects. Pool is not meant for storage. If there
17  ///    is no space in the pool, extra returned objects will be dropped.
18  ///
19  /// 2) it is implied that if object was obtained from a pool, the caller will return it back in
20  ///    a relatively short time. Keeping checked out objects for long durations is ok, but
21  ///    reduces usefulness of pooling. Just new up your own.
22  ///
23  /// Not returning objects to the pool in not detrimental to the pool's work, but is a bad practice.
24  /// Rationale:
25  ///    If there is no intent for reusing the object, do not use pool - just use "new".
26  /// </summary>
27  internal sealed class ObjectPool<T> where T : class {
28    private struct Element {
29      internal T Value;
30    }
31
32    // storage for the pool objects.
33    private readonly Element[] _items;
34
35    // factory is stored for the lifetime of the pool. We will call this only when pool needs to
36    // expand. compared to "new T()", Func gives more flexibility to implementers and faster
37    // than "new T()".
38    private readonly Func<T> _factory;
39
40
41    internal ObjectPool(Func<T> factory)
42        : this(factory, Environment.ProcessorCount * 2) { }
43
44    internal ObjectPool(Func<T> factory, int size) {
45      _factory = factory;
46      _items = new Element[size];
47    }
48
49    private T CreateInstance() {
50      var inst = _factory();
51      return inst;
52    }
53
54    /// <summary>
55    /// Produces an instance.
56    /// </summary>
57    /// <remarks>
58    /// Search strategy is a simple linear probing which is chosen for it cache-friendliness.
59    /// Note that Free will try to store recycled objects close to the start thus statistically
60    /// reducing how far we will typically search.
61    /// </remarks>
62    internal T Allocate() {
63      var items = _items;
64      T inst;
65
66      for (int i = 0; i < items.Length; i++) {
67        // Note that the read is optimistically not synchronized. That is intentional.
68        // We will interlock only when we have a candidate. in a worst case we may miss some
69        // recently returned objects. Not a big deal.
70        inst = items[i].Value;
71        if (inst != null) {
72          if (inst == Interlocked.CompareExchange(ref items[i].Value, null, inst)) {
73            goto gotInstance;
74          }
75        }
76      }
77
78      inst = CreateInstance();
79      gotInstance:
80
81      return inst;
82    }
83
84    /// <summary>
85    /// Returns objects to the pool.
86    /// </summary>
87    /// <remarks>
88    /// Search strategy is a simple linear probing which is chosen for it cache-friendliness.
89    /// Note that Free will try to store recycled objects close to the start thus statistically
90    /// reducing how far we will typically search in Allocate.
91    /// </remarks>
92    internal void Free(T obj) {
93      var items = _items;
94      for (int i = 0; i < items.Length; i++) {
95        if (items[i].Value == null) {
96          // Intentionally not using interlocked here.
97          // In a worst case scenario two objects may be stored into same slot.
98          // It is very unlikely to happen and will only mean that one of the objects will get collected.
99          items[i].Value = obj;
100          break;
101        }
102      }
103    }
104  }
105}
Note: See TracBrowser for help on using the repository browser.