Apollo 3.5 Cyber base代碼學習
-
- `cyber/base/macros.h`
- `cyber/base/atomic_fifo.h`
- `cyber/base/for_each.h`
- `cyber/base/wait_strategy`
- `cyber/base/atomic_hash_map.h`
- `cyber/base/rw_lock_guard`
- `cyber/base/atomic_rw_lock`
- `cyber/base/bounded_queue`
- `cyber/base/concurrent_object_pool`
- `cyber/base/object_pool`
- `cyber/base/reentrant_rw_lock`
- `cyber/base/signal`
- `cyber/base/thread_pool`
- `cyber/base/thread_safe_queue`
- `cyber/base/unbounded_queue`
// Study: 是我的筆記
base中主要是一些thread safe的容器跟鎖等基本工具, 值得一看
cyber/base/macros.h
/******************************************************************************
* Copyright 2018 The Apollo Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*****************************************************************************/
#ifndef CYBER_BASE_MACROS_H_
#define CYBER_BASE_MACROS_H_
#include <cstdlib>
#include <new>
// Study: __builtin_expect is a function to let the compiler know the chance of the condition to be true
// , the compiler can do optimization in assembly level using this information
#if __GNUC__ >= 3
#define likely(x) (__builtin_expect((x), 1))
#define unlikely(x) (__builtin_expect((x), 0))
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif
// Study: The size of cache line, cache line is the a block that will be fetch from memory to cache
#define CACHELINE_SIZE 64
// Study: Meta-programming, used SFINTE. When the T type have the `func` function, it will be true,
// Otherwise it is false (since size of int is not 1)
// basically used to determine the exist of the func for T in compile time
// Can be mixed with the stl traits
#define DEFINE_TYPE_TRAIT(name, func) \
template <typename T> \
class name { \
private: \
template <typename Class> \
static char Test(decltype(&Class::func)*); \
template <typename> \
static int Test(...); \
\
public: \
static constexpr bool value = sizeof(Test<T>(nullptr)) == 1; \
}; \
\
template <typename T> \
constexpr bool name<T>::value;
// Study: Call the processer to pause (no operation)
// The different of rep;nop; to nop;nop; is that processor can optimize with this
inline void cpu_relax() {
asm volatile("rep; nop" ::: "memory"); }
// Study: Allocate memory
inline void* CheckedMalloc(size_t size) {
void* ptr = std::malloc(size);
if (!ptr) {
throw std::bad_alloc();
}
return ptr;
}
// Study: Allocate memory and Clean location
inline void* CheckedCalloc(size_t num, size_t size) {
void* ptr = std::calloc(num, size);
if (!ptr) {
throw std::bad_alloc();
}
return ptr;
}
#endif // CYBER_BASE_MACROS_H_
cyber/base/atomic_fifo.h
/******************************************************************************
* Copyright 2018 The Apollo Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*****************************************************************************/
#ifndef CYBER_BASE_ATOMIC_FIFO_H_
#define CYBER_BASE_ATOMIC_FIFO_H_
#include <atomic>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include "cyber/base/macros.h"
namespace apollo {
namespace cyber {
template <typename T>
class AtomicFIFO {
private:
struct Node {
T value;
};
public:
// Study: Singleton
static AtomicFIFO *GetInstance(int cap = 100) {
static AtomicFIFO *inst = new AtomicFIFO(cap);
return inst;
}
bool Push(const T &value);
bool Pop(T *value);
// insert();
private:
Node *node_arena_;
// Study: Align to maximize the memory access speed
alignas(CACHELINE_SIZE) std::atomic<uint32_t> head_;
alignas(CACHELINE_SIZE) std::atomic<uint32_t> commit_;
alignas(CACHELINE_SIZE) std::atomic<uint32_t> tail_;
int capacity_;
// Study: Only allow Singleton
explicit AtomicFIFO(int cap);
~AtomicFIFO();
AtomicFIFO(AtomicFIFO &) = delete;
AtomicFIFO &operator=(AtomicFIFO &) = delete;
};
template <typename T>
AtomicFIFO<T>::AtomicFIFO(int cap) : capacity_(cap) {
node_arena_ = static_cast<Node *>(malloc(capacity_ * sizeof(Node)));
memset(node_arena_, 0, capacity_ * sizeof(Node));
// Study: Set value to 0
head_.store(0, std::memory_order_relaxed);
tail_.store(0, std::memory_order_relaxed);
commit_.store(0, std::memory_order_relaxed);
}
template <typename T>
AtomicFIFO<T>::~AtomicFIFO() {
if (node_arena_ != nullptr) {
for (int i = 0; i < capacity_; i++) {
// Study: Call the T destructor manaully, since it is puted in the malloc region, it will not auto destruct
node_arena_[i].value.~T();
}
free(node_arena_);
}
}
template <typename T>
bool AtomicFIFO<T>::Push(const T &value) {
uint32_t oldt, newt;
// Study: Try push until success, return false if queue full
oldt = tail_.load(std::memory_order_acquire);
do {
uint32_t h = head_.load(std::memory_order_acquire);
uint32_t t = tail_.load(std::memory_order_acquire);
if (((t + 1) % capacity_) == h) return false;
newt = (oldt + 1) % capacity_;
// Study: If success, set tail_ to newt, otherwise set oldt to current tail_
// Ensure tails value sync
} while (!tail_.compare_exchange_weak(oldt, newt, std::memory_order_acq_rel,
std::memory_order_acquire));
(node_arena_ + oldt)->value = value;
// Study: commit_ is basically same as tail_, but it is used in pop.
// It can let the pop operation not block the push core part
while (unlikely(commit_.load(std::memory_order_acquire) != oldt)) cpu_relax();
// Study: After commit, this value can be pop in Pop()
commit_.store(newt, std::memory_order_release);
return true;
}
template <typename T>
bool AtomicFIFO<T>::Pop(T *value) {
uint32_t oldh, newh;
oldh = head_.load(std::memory_order_acquire);
// Study: Basically same logic as the push part, try pop until success. Return false if no element
do {
uint32_t h = head_.load(std::memory_order_acquire);
uint32_t c = commit_.load(std::memory_order_acquire);
if (h == c) return false;
newh = (oldh + 1) % capacity_;
*value = (node_arena_ + oldh)->value;
} while (!head_.compare_exchange_weak(oldh, newh, std::memory_order_acq_rel,
std::memory_order_acquire));
return true;
}
} // namespace cyber
} // namespace apollo
#endif // CYBER_BASE_ATOMIC_FIFO_H_
cyber/base/for_each.h
/******************************************************************************
* Copyright 2018 The Apollo Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*****************************************************************************/
#ifndef CYBER_BASE_FOR_EACH_H_
#define CYBER_BASE_FOR_EACH_H_
#include <type_traits>
#include "cyber/base/macros.h"
namespace apollo {
namespace cyber {
namespace base {
// Study: A trait to check whether the class have impl operator <
DEFINE_TYPE_TRAIT(HasLess, operator<) // NOLINT
// Study: If both of them have impl <, use it
template <class Value, class End>
typename std::enable_if<HasLess<Value>::value && HasLess<End>::value,
bool>::type
LessThan(const Value& val, const End& end) {
return val < end;
}
// Study: Otherwise, check equality.....
// Actually, I thing this function name is misleading. This will only make sense when using in FOR_EACH
template <class Value, class End>
typename std::enable_if<!HasLess<Value>::value || !HasLess<End>::value,
bool>::type
LessThan(const Value& val, const End& end) {
return val != end;
}
// Study: Loop until end, Be careful that i should not be a index, it should be a iterator or something similiar
#define FOR_EACH(i, begin, end) \
for (auto i = (true ? (begin) : (end)); \
apollo::cyber::base::LessThan(i, (end)); ++i)
} // namespace base
} // namespace cyber
} // namespace apollo
#endif // CYBER_BASE_FOR_EACH_H_
cyber/base/wait_strategy
/******************************************************************************
* Copyright 2018 The Apollo Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*****************************************************************************/
#ifndef CYBER_BASE_WAIT_STRATEGY_H_
#define CYBER_BASE_WAIT_STRATEGY_H_
#include <chrono>
#include <condition_variable>
#include <cstdlib>
#include <mutex>
#include <thread>
namespace apollo {
namespace cyber {
namespace base {
class WaitStrategy {
public:
// Study: One waiter is allow to pass
virtual void NotifyOne() {
}
// Study: All waiter is allow to pass
virtual void BreakAllWait() {
}
// Study: Wait here
virtual bool EmptyWait() = 0;
virtual ~WaitStrategy() {
}
};
// Study: Blocked until allow to pass
class BlockWaitStrategy : public WaitStrategy {
public:
BlockWaitStrategy() {
}
void NotifyOne() override {
cv_.notify_one(); }
bool EmptyWait() override {
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait(lock);
return true;
}
void BreakAllWait() {
cv_.notify_all(); }
private:
std::mutex mutex_;
std::condition_variable cv_;
};
// Study: Sleeped and pass after the sleep time
class SleepWaitStrategy : public WaitStrategy {
public:
SleepWaitStrategy() {
}
explicit SleepWaitStrategy(uint64_t sleep_time_us)
: sleep_time_us_(sleep_time_us) {
}
bool EmptyWait() override {
std::this_thread::sleep_for(std::chrono::microseconds(sleep_time_us_));
return true;
}
void SetSleepTimeMicroSecends(uint64_t sleep_time_us)


1732

被折叠的 条评论
为什么被折叠?



