Apollo  6.0
Open source self driving car software
concurrent_object_pool.h
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright 2018 The Apollo Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *****************************************************************************/
16 
17 #ifndef CYBER_BASE_CONCURRENT_OBJECT_POOL_H_
18 #define CYBER_BASE_CONCURRENT_OBJECT_POOL_H_
19 
20 #include <atomic>
21 #include <cstdlib>
22 #include <cstring>
23 #include <iostream>
24 #include <memory>
25 #include <stdexcept>
26 #include <utility>
27 
28 #include "cyber/base/for_each.h"
29 #include "cyber/base/macros.h"
30 
31 namespace apollo {
32 namespace cyber {
33 namespace base {
34 
35 template <typename T>
36 class CCObjectPool : public std::enable_shared_from_this<CCObjectPool<T>> {
37  public:
38  explicit CCObjectPool(uint32_t size);
39  virtual ~CCObjectPool();
40 
41  template <typename... Args>
42  void ConstructAll(Args &&... args);
43 
44  template <typename... Args>
45  std::shared_ptr<T> ConstructObject(Args &&... args);
46 
47  std::shared_ptr<T> GetObject();
48  void ReleaseObject(T *);
49  uint32_t size() const;
50 
51  private:
52  struct Node {
53  T object;
54  Node *next;
55  };
56 
57  struct alignas(2 * sizeof(Node *)) Head {
58  uintptr_t count;
59  Node *node;
60  };
61 
62  private:
63  CCObjectPool(CCObjectPool &) = delete;
64  CCObjectPool &operator=(CCObjectPool &) = delete;
65  bool FindFreeHead(Head *head);
66 
67  std::atomic<Head> free_head_;
68  Node *node_arena_ = nullptr;
69  uint32_t capacity_ = 0;
70 };
71 
72 template <typename T>
73 CCObjectPool<T>::CCObjectPool(uint32_t size) : capacity_(size) {
74  node_arena_ = static_cast<Node *>(CheckedCalloc(capacity_, sizeof(Node)));
75  FOR_EACH(i, 0, capacity_ - 1) { node_arena_[i].next = node_arena_ + 1 + i; }
76  node_arena_[capacity_ - 1].next = nullptr;
77  free_head_.store({0, node_arena_}, std::memory_order_relaxed);
78 }
79 
80 template <typename T>
81 template <typename... Args>
82 void CCObjectPool<T>::ConstructAll(Args &&... args) {
83  FOR_EACH(i, 0, capacity_) {
84  new (node_arena_ + i) T(std::forward<Args>(args)...);
85  }
86 }
87 
88 template <typename T>
90  std::free(node_arena_);
91 }
92 
93 template <typename T>
94 bool CCObjectPool<T>::FindFreeHead(Head *head) {
95  Head new_head;
96  Head old_head = free_head_.load(std::memory_order_acquire);
97  do {
98  if (cyber_unlikely(old_head.node == nullptr)) {
99  return false;
100  }
101  new_head.node = old_head.node->next;
102  new_head.count = old_head.count + 1;
103  } while (!free_head_.compare_exchange_weak(old_head, new_head,
104  std::memory_order_acq_rel,
105  std::memory_order_acquire));
106  *head = old_head;
107  return true;
108 }
109 
110 template <typename T>
111 std::shared_ptr<T> CCObjectPool<T>::GetObject() {
112  Head free_head;
113  if (cyber_unlikely(!FindFreeHead(&free_head))) {
114  return nullptr;
115  }
116  auto self = this->shared_from_this();
117  return std::shared_ptr<T>(reinterpret_cast<T *>(free_head.node),
118  [self](T *object) { self->ReleaseObject(object); });
119 }
120 
121 template <typename T>
122 template <typename... Args>
123 std::shared_ptr<T> CCObjectPool<T>::ConstructObject(Args &&... args) {
124  Head free_head;
125  if (cyber_unlikely(!FindFreeHead(&free_head))) {
126  return nullptr;
127  }
128  auto self = this->shared_from_this();
129  T *ptr = new (free_head.node) T(std::forward<Args>(args)...);
130  return std::shared_ptr<T>(ptr, [self](T *object) {
131  object->~T();
132  self->ReleaseObject(object);
133  });
134 }
135 
136 template <typename T>
138  Head new_head;
139  Node *node = reinterpret_cast<Node *>(object);
140  Head old_head = free_head_.load(std::memory_order_acquire);
141  do {
142  node->next = old_head.node;
143  new_head.node = node;
144  new_head.count = old_head.count + 1;
145  } while (!free_head_.compare_exchange_weak(old_head, new_head,
146  std::memory_order_acq_rel,
147  std::memory_order_acquire));
148 }
149 
150 } // namespace base
151 } // namespace cyber
152 } // namespace apollo
153 
154 #endif // CYBER_BASE_CONCURRENT_OBJECT_POOL_H_
void ConstructAll(Args &&... args)
Definition: concurrent_object_pool.h:82
virtual ~CCObjectPool()
Definition: concurrent_object_pool.h:89
PlanningContext is the runtime context in planning. It is persistent across multiple frames...
Definition: atomic_hash_map.h:25
std::shared_ptr< T > ConstructObject(Args &&... args)
Definition: concurrent_object_pool.h:123
void ReleaseObject(T *)
Definition: concurrent_object_pool.h:137
#define FOR_EACH(i, begin, end)
Definition: for_each.h:44
CCObjectPool(uint32_t size)
Definition: concurrent_object_pool.h:73
Definition: concurrent_object_pool.h:36
void * CheckedCalloc(size_t num, size_t size)
Definition: macros.h:67
std::shared_ptr< T > GetObject()
Definition: concurrent_object_pool.h:111
#define cyber_unlikely(x)
Definition: macros.h:28