Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifndef CARTOGRAPHER_COMMON_LOCKLESS_QUEUE_H_
00018 #define CARTOGRAPHER_COMMON_LOCKLESS_QUEUE_H_
00019
00020 #include <atomic>
00021 #include <memory>
00022
00023 #include "absl/memory/memory.h"
00024 #include "glog/logging.h"
00025
00026 namespace cartographer {
00027 namespace common {
00028
00029
00030
00031
00032
00033
00034 template <typename T>
00035 class LocklessQueue {
00036 public:
00037 LocklessQueue() {
00038 free_list_head_ = nullptr;
00039 incoming_data_list_head_ = nullptr;
00040 data_list_head_ = nullptr;
00041 data_list_tail_ = nullptr;
00042 }
00043
00044 ~LocklessQueue() {
00045 FreeNodes(free_list_head_.exchange(nullptr));
00046 FreeNodes(incoming_data_list_head_.exchange(nullptr));
00047 FreeNodes(data_list_head_);
00048 }
00049
00050
00051 void Push(std::unique_ptr<T> t) {
00052 Node* const free_node = PopNodeFromFreeList();
00053 CHECK(free_node);
00054 free_node->data = std::move(t);
00055 PushNodeToList(&incoming_data_list_head_, free_node);
00056 }
00057
00058
00059
00060 std::unique_ptr<T> Pop() {
00061 SwapLists();
00062 if (data_list_head_ != nullptr) {
00063 Node* node = data_list_head_;
00064 data_list_head_ = data_list_head_->next;
00065 std::unique_ptr<T> data = std::move(node->data);
00066 PushNodeToList(&free_list_head_, node);
00067 return std::move(data);
00068 }
00069 return nullptr;
00070 }
00071
00072 private:
00073
00074 struct Node {
00075 Node() = default;
00076
00077
00078 Node(const Node& node) : next() {}
00079
00080
00081 std::unique_ptr<T> data;
00082
00083
00084 std::atomic<Node*> next;
00085 };
00086
00087
00088 void FreeNodes(Node* node) {
00089 while (node != nullptr) {
00090 Node* next_node_ptr = node->next;
00091 delete node;
00092 node = next_node_ptr;
00093 }
00094 }
00095
00096
00097 void PushNodeToList(std::atomic<Node*>* list_head, Node* node) {
00098 DCHECK(list_head);
00099 DCHECK(node);
00100 Node* list_head_ptr;
00101 do {
00102 list_head_ptr = list_head->load();
00103 node->next = list_head_ptr;
00104 } while (!std::atomic_compare_exchange_strong_explicit(
00105 list_head, &list_head_ptr, node, std::memory_order_release,
00106 std::memory_order_relaxed));
00107 }
00108
00109
00110
00111 Node* PopNodeFromFreeList() {
00112 Node* list_head_ptr;
00113 Node* list_head_next_ptr;
00114 do {
00115 list_head_ptr = free_list_head_.load();
00116 if (list_head_ptr == nullptr) {
00117 return new Node;
00118 }
00119 list_head_next_ptr = list_head_ptr->next.load();
00120 } while (!std::atomic_compare_exchange_strong_explicit(
00121 &free_list_head_, &list_head_ptr, list_head_next_ptr,
00122 std::memory_order_relaxed, std::memory_order_relaxed));
00123 return list_head_ptr;
00124 }
00125
00126
00127
00128 void SwapLists() {
00129 Node* node_itr = incoming_data_list_head_.exchange(nullptr);
00130 if (node_itr == nullptr) {
00131
00132 return;
00133 }
00134
00135
00136 Node* const data_list_tail = node_itr;
00137
00138
00139
00140 Node* prev_node_itr = nullptr;
00141 while (node_itr != nullptr) {
00142 Node* const next_node_ptr = node_itr->next;
00143 node_itr->next = prev_node_itr;
00144 prev_node_itr = node_itr;
00145 node_itr = next_node_ptr;
00146 }
00147
00148
00149
00150 if (data_list_tail_ == nullptr) {
00151 data_list_head_ = prev_node_itr;
00152 } else {
00153 data_list_tail_->next = prev_node_itr;
00154 }
00155 data_list_tail_ = data_list_tail;
00156 }
00157
00158
00159 std::atomic<Node*> free_list_head_;
00160
00161
00162 std::atomic<Node*> incoming_data_list_head_;
00163
00164
00165 Node* data_list_head_;
00166
00167
00168 Node* data_list_tail_;
00169 };
00170
00171 }
00172 }
00173
00174 #endif // CARTOGRAPHER_COMMON_LOCKLESS_QUEUE_H_